I have a table like this:
id col1 col2 col3
10 1 3
9 1 2 3
8 2 3
7 2 3
6 1 2
5 3
Each column has one value only or null. Eg. Col1 has 1 or empty. Col2 has 2 or empty.
I'd like to get the sum of repeating values only between two successive rows.
so the result would look like this:
I need to get the sum of total repeating values in each row.
id col1 col2 col3 Count
10 1 3 2 (shows the repeating values between id10 & id9 rows)
9 1 2 3 2 (shows the repeating values between id9 & id8 rows)
8 2 3 1
7 2 1
6 1 2 0
5 3
I googled and tried some queries I found on the web but couldn't get the right result. Thanks in advance for your help.
To further clarify, for example:
id10 row has (1,,3) and id9 row has (1,2,3). so there is two values repeating. so count is 2.
If the ids are consecutive and there are no gaps, you can do it with a self join:
select
t.*,
coalesce((t.col1 = tt.col1), 0) +
coalesce((t.col2 = tt.col2), 0) +
coalesce((t.col3 = tt.col3), 0) count
from tablename t left join tablename tt
on tt.id = t.id - 1
See the demo.
Results:
| id | col1 | col2 | col3 | count |
| --- | ---- | ---- | ---- | ----- |
| 10 | 1 | | 3 | 2 |
| 9 | 1 | 2 | 3 | 2 |
| 8 | | 2 | 3 | 1 |
| 7 | | 2 | | 1 |
| 6 | 1 | 2 | | 0 |
| 5 | | | 3 | 0 |
And if there are gaps...
SELECT a.id
, a.col1
, a.col2
, a.col3
, COALESCE(a.col1 = b.col1,0) + COALESCE(a.col2 = b.col2,0) + COALESCE(a.col3 = b.col3,0) n
FROM
( SELECT x.*
, MIN(y.id) y_id
FROM my_table x
JOIN my_table y
ON y.id > x.id
GROUP
BY x.id
) a
LEFT
JOIN my_table b
ON b.id = a.y_id;
Were you to restructure your schema, then you could do something like this instead...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL
,val INT NOT NULL
,PRIMARY KEY(id,val)
);
INSERT INTO my_table VALUES
(10,1),
(10,3),
( 9,1),
( 9,2),
( 9,3),
( 8,2),
( 8,3),
( 7,2),
( 7,3),
( 6,1),
( 6,2),
( 5,3);
SELECT a.id
, COUNT(b.id) total
FROM
( SELECT x.*
, MIN(y.id) next
FROM my_table x
JOIN my_table y
ON y.id > x.id
GROUP
BY x.id
, x.val
) a
LEFT
JOIN my_table b
ON b.id = a.next
AND b.val = a.val
GROUP
BY a.id;
+----+-------+
| id | total |
+----+-------+
| 5 | 0 |
| 6 | 1 |
| 7 | 2 |
| 8 | 2 |
| 9 | 2 |
+----+-------+
You can use :
select t1_ID, t1_col1,t1_col2,t1_col3, count
from
(
select t1.id as t1_ID, t1.col1 as t1_col1,t1.col2 as t1_col2,t1.col3 as t1_col3, t2.*,
case when t1.col1 = t2.col1 then 1 else 0 end +
case when t1.col2 = t2.col2 then 1 else 0 end +
case when t1.col3 = t2.col3 then 1 else 0 end as count
from tab t1
left join tab t2
on t1.id = t2.id + 1
order by t1.id
) t3
order by t1_ID desc;
Demo
If there are gaps between id values for the next row, you could have user defined variables to explicitly assign values to rows in their natural ordering in the table. Rest logic remains the same as already answered. You would do an inner join between current row number and next row number to get the col1,col2 and col3 values and use coalesce for computation of count.
select derived_1.*,
coalesce((derived_1.col1 = derived_2.col1), 0) +
coalesce((derived_1.col2 = derived_2.col2), 0) +
coalesce((derived_1.col3 = derived_2.col3), 0) count
from (
select #row := #row + 1 as row_number,t1.*
from tablename t1,(select #row := 0) d1
) derived_1
left join (
select *
from (
select #row2 := #row2 + 1 as row_number,t2.*
from tablename t2,(select #row2 := 0) d2
) d3
) derived_2
on derived_1.row_number + 1 = derived_2.row_number;
Demo: https://www.db-fiddle.com/f/wAzb67zSEfbZKg5RywQvC8/1
I have table with 3 columns : A, B and C. These columns can be true or false.
I want to get count of every possible combination.
Sample data:
CREATE TABLE `myTable` (
`id` mediumint(8) unsigned NOT NULL auto_increment,
`A` mediumint default NULL,
`B` mediumint default NULL,
`C` mediumint default NULL,
PRIMARY KEY (`id`)
) AUTO_INCREMENT=1;
INSERT INTO `myTable` (`A`,`B`,`C`) VALUES (0,0,1),(1,1,0),(0,0,0),(1,1,0),(1,0,0),(1,0,1),(0,0,1),(1,1,1),(0,1,0),(1,1,1);
INSERT INTO `myTable` (`A`,`B`,`C`) VALUES (1,0,1),(0,1,0),(1,1,1),(0,0,1),(1,0,0),(0,0,0),(0,0,1),(1,1,0),(0,0,0),(1,1,0);
INSERT INTO `myTable` (`A`,`B`,`C`) VALUES (1,1,0),(0,1,0),(1,1,1),(0,0,0),(1,1,0),(1,0,1),(1,1,1),(1,0,1),(1,1,1),(1,1,1);
INSERT INTO `myTable` (`A`,`B`,`C`) VALUES (0,1,0),(1,0,0),(0,1,0),(0,0,0),(0,0,0),(1,0,0),(1,0,1),(1,1,1),(0,0,1),(0,0,0);
INSERT INTO `myTable` (`A`,`B`,`C`) VALUES (1,1,1),(0,0,1),(1,1,0),(1,1,0),(1,0,0),(0,0,1),(0,1,1),(1,0,1),(1,0,0),(1,1,0);
INSERT INTO `myTable` (`A`,`B`,`C`) VALUES (1,1,1),(0,0,0),(1,0,1),(1,0,0),(1,0,0),(1,0,0),(0,0,1),(1,1,1),(0,1,1),(1,1,0);
INSERT INTO `myTable` (`A`,`B`,`C`) VALUES (0,1,1),(0,1,1),(0,1,0),(0,0,0),(0,1,0),(0,1,1),(0,1,1),(0,1,1),(0,1,0),(0,1,0);
INSERT INTO `myTable` (`A`,`B`,`C`) VALUES (0,1,1),(0,0,1),(0,1,0),(1,1,0),(0,0,0),(1,1,1),(1,1,0),(0,1,1),(1,0,1),(1,0,0);
INSERT INTO `myTable` (`A`,`B`,`C`) VALUES (0,1,0),(1,1,1),(0,1,0),(1,1,0),(1,0,1),(1,1,0),(0,1,0),(0,1,0),(0,1,0),(0,1,0);
INSERT INTO `myTable` (`A`,`B`,`C`) VALUES (1,1,0),(0,1,0),(1,1,1),(0,0,0),(1,0,0),(1,1,0),(1,0,1),(0,0,1),(1,0,1),(1,0,0);
Example result (from sample data):
combination: count
none: 11
A: 12
B: 17
C: 10
AB: 16
BC: 9
AC: 11
ABC: 14
Is this possible in one query? (MySQL)
This appears to be a simple count and Group by.
SELECT A, B, C, count(*)
FROM MyTable
GROUP BY A, B, C;
DEMO:
If you want you can show the string of values combined use concat and case...
SELECT concat(case when A = 1 then 'A' else '' end,
case when B = 1 then 'B' else '' end,
case when C = 1 then 'C' else '' end) as Combination
, count(*)
FROM MyTable
GROUP BY A, B, C
ORDER BY Combination;
or as Paul Spiegel shows in comments:
SELECT concat(left('A', A), left('B', B), left('C', C)) as Combination
, count(*)
FROM MyTable
GROUP BY A, B, C
ORDER BY Combination;
Giving us:
+----+-------------+----------+
| | Combination | count(*) |
+----+-------------+----------+
| 1 | | 11 |
| 2 | A | 12 |
| 3 | AB | 16 |
| 4 | ABC | 14 |
| 5 | AC | 11 |
| 6 | B | 17 |
| 7 | BC | 9 |
| 8 | C | 10 |
+----+-------------+----------+
Assuming your combinations are where those columns' values are TRUE, you're just looking at a group by over those 3 columns. The case logic is just there to present the combo in a single column; you could easily replace "case...end" with "A, B, C" to get the same result with those columns showing their values separately.
select
case
when A = 1 and B = 1 and C = 1 then 'ABC'
when A = 1 and B = 1 and C = 0 then 'AB'
when A = 1 and B = 0 and C = 1 then 'AC'
when A = 0 and B = 1 and C = 1 then 'BC'
when A = 1 and B = 0 and C = 0 then 'A'
when A = 0 and B = 1 and C = 0 then 'B'
when A = 0 and B = 0 and C = 1 then 'C'
else 'oops, this should not happen'
end as `Combo`
--, sum(sumThing) as `sum` --amended to count per question edit
, count(*) as `count`
from myTable
where A = true
or B = true
or C = true
group by A, B, C
Use conditional count
SELECT
COUNT(CASE WHEN A=1 THEN 1 END) AS A,
COUNT(CASE WHEN B=1 THEN 1 END) AS B,
COUNT(CASE WHEN C=1 THEN 1 END) AS C,
COUNT(CASE WHEN A=1 AND B=1 THEN 1 END) AS AB,
COUNT(CASE WHEN A=1 AND C=1 THEN 1 END) AS AC,
COUNT(CASE WHEN B=1 AND C=1 THEN 1 END) AS BC,
COUNT(CASE WHEN A=1 AND B=1 AND C=1 THEN 1 END) AS ABC,
COUNT(CASE WHEN A<>1 AND B<>1 AND C<>1 THEN 1 END) AS None
FROM table1;
You can use a simple subquery for each combination and union them:
SELECT "none", COUNT(*) FROM mytable WHERE A = 0 AND B = 0 AND C = 0
UNION
SELECT "A", COUNT(*) FROM mytable WHERE A = 1 AND B = 0 AND C = 0
UNION
SELECT "B", COUNT(*) FROM mytable WHERE A = 0 AND B = 1 AND C = 0
UNION
SELECT "C", COUNT(*) FROM mytable WHERE A = 0 AND B = 0 AND C = 1
UNION
SELECT "AB", COUNT(*) FROM mytable WHERE A = 1 AND B = 1 AND C = 0
UNION
SELECT "BC", COUNT(*) FROM mytable WHERE A = 0 AND B = 1 AND C = 1
UNION
SELECT "AC", COUNT(*) FROM mytable WHERE A = 1 AND B = 0 AND C = 1
UNION
SELECT "ABC", COUNT(*) FROM mytable WHERE A = 1 AND B = 1 AND C = 1
I have a table named question_dispositions composed like this
Type | chapter | number
-------------------------
A | 1 | 3
B | 1 | 2
B | 4 | 1
The second table named question has columns type, text and chapter.
Type | chapter | text
-----------------------
A | 1 | T1
A | 1 | T2
B | 1 | T3
B | 1 | T4
B | 1 | T5
B | 2 | T6
B | 2 | T7
B | 3 | T8
B | 4 | T9
What I need is to fetch X random questions from table Question where the X is the column number from question_dispositions
So if I need questions of type B the result that I expect is this:
chapter | text
--------------
1 | T3
1 | T4
4 | T9
How can I Select random question limiting by the column number in another table? I tried with this query but returns every row in the table Question as expected because I can not limit with qd.count
SELECT * FROM
question_dispositions AS qd, question AS q
WHERE qd.chapter = q.chapter AND qd.type = q.type AND qd.type = 'B'
ORDER BY RAND() is a typical approach to randomness in MySQL but it is usually criticized because it does not scale well. Here however you appear to be selecting a quite small number of rows as questions but to achieve some randomness of those. So, here is an approach using ORDER BY RAND() which should be acceptable in performance for small result sets.
There is an added requirement to LIMIT by a stored Number, however in the small example supplied that number isn't consistent for type B so I chose to limit by the maximum of that number for the wanted type B. MySQL doesn't allow use of variables or subqueries with the LIMIT clause so instead a generated row number is used in a where clause to achieve that outcome.
Refer to this SQL Fiddle
Data:
CREATE TABLE question_dispositions
(`Type` varchar(1), `chapter` int, `number` int)
;
INSERT INTO question_dispositions
(`Type`, `chapter`, `number`)
VALUES
('A', 1, 3),
('B', 1, 2),
('B', 4, 1)
;
CREATE TABLE question
(`Type` varchar(1), `chapter` int, `text` varchar(2))
;
INSERT INTO question
(`Type`, `chapter`, `text`)
VALUES
('A', 1, 'T1'),
('A', 1, 'T2'),
('B', 1, 'T3'),
('B', 1, 'T4'),
('B', 1, 'T5'),
('B', 2, 'T6'),
('B', 2, 'T7'),
('B', 3, 'T8'),
('B', 4, 'T9')
;
Query:
SELECT *
FROM (
SELECT #rownum := #rownum + 1 AS rn , q.*
FROM question_dispositions AS qd
INNER JOIN question AS q ON qd.chapter = q.chapter AND qd.type = q.type
CROSS JOIN (SELECT #rownum := 0) r
WHERE qd.type = 'B'
ORDER BY RAND()
) d
WHERE rn <= (SELECT MAX(NUMBER) FROM question_dispositions WHERE type = 'B')
Example Results:
| rn | Type | chapter | text |
|----|------|---------|------|
| 1 | B | 1 | T3 |
| 2 | B | 1 | T4 |
To assist in understanding I have a table like this:
itemcode itemname icode serialnum
1 A 10 0
2 B 10 0
3 C 10 0
4 D 11 0
5 E 13 0
6 F 20 0
7 G 20 0
I want the result to look like the table below using a single update query with the help of looping cursors:
itemcode itemname icode serialnum
1 A 10 1
2 B 10 2
3 C 10 3
4 D 11 1
5 E 13 1
6 F 20 1
7 G 20 2
Item code is the primary key in this table. The logic behind generating the serial number is whenever icode changes the serial number gets reset to 1. I need a single update query to update the table with the help of cursors if someone can assist with a solution?
So you want a sequential serial number for every icode-group. Then you can use ROW_NUMBER with PARTITION BY icode:
WITH CTE AS
(
SELECT itemcode, itemname, icode, serialnum,
, ROW_NUMBER() OVER (PARTITION BY icode ORDER BY itemcode) AS RN
FROM dbo.TableName
)
UPDATE CTE SET serialnum = RN;
If you want it to be reculculated on every update you could use a trigger:
CREATE TRIGGER dbo.TableName_Updated
ON dbo.TableName
FOR UPDATE /* Fire this trigger when one or multiple rows are UPDATEd */
AS BEGIN
WITH CTE AS
(
SELECT itemcode, itemname, icode, serialnum,
, ROW_NUMBER() OVER (PARTITION BY icode ORDER BY itemcode) AS RN
FROM dbo.TableName t INNER JOIN INSERTED i
ON t.itemcode = i.itemcode
)
UPDATE CTE SET serialnum = RN
END
SQL Fiddle
MS SQL Server 2008 Schema Setup:
create table Item
(
itemcode int,
itemname char(1),
icode int,
serialnum int
)
insert into Item values
(1, 'A', 10, 0),
(2, 'B', 20, 0),
(3, 'C', 11, 0),
(4, 'D', 10, 0),
(5, 'E', 20, 0),
(6, 'F', 10, 0),
(7, 'G', 13, 0)
Query 1:
update I
set serialnum = rn
from
(
select serialnum,
row_number() over(partition by icode order by itemcode) as rn
from Item
) I
select *
from Item
Results:
| ITEMCODE | ITEMNAME | ICODE | SERIALNUM |
-------------------------------------------
| 1 | A | 10 | 1 |
| 2 | B | 20 | 1 |
| 3 | C | 11 | 1 |
| 4 | D | 10 | 2 |
| 5 | E | 20 | 2 |
| 6 | F | 10 | 3 |
| 7 | G | 13 | 1 |
Update
A version that uses a cursor instead of not using a cursor.
SQL Fiddle
declare #itemcode int
declare #rn int
declare ItemCursor cursor local static forward_only read_only for
select itemcode,
row_number() over(partition by icode order by itemcode) as rn
from Item
open ItemCursor
fetch next from ItemCursor
into #itemcode, #rn
while ##fetch_status = 0
begin
update Item
set serialnum = #rn
where itemcode = #itemcode
fetch next from ItemCursor
into #itemcode, #rn
end
close ItemCursor
deallocate ItemCursor