Reputation: 63
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.
Upvotes: 2
Views: 224
Reputation: 17805
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
Upvotes: 1
Reputation: 33935
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 |
+----+-------+
Upvotes: 2
Reputation: 65218
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;
Upvotes: 1
Reputation: 164089
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 |
Upvotes: 2