Group by adjacent rows based on two columns - mysql

Let's say I have a table like this:
id col1 col2
---------------------
1 35 A
2 40 B
3 39 B
4 39 B
5 39 B
6 40 B
7 39 B
8 39 B
9 40 B
10 40 C
11 35 C
How do I make it so that it has a result like this:
id col1 col2
---------------------
1 35 A
2 40 B
3 39 B
6 40 B
7 39 B
9 40 B
10 40 C
11 35 C
I want to group by col1 that has same value in adjacent rows while also has same group in col2 (col1 values in id:9 and id:10 couldn't be grouped because it has different col2 value)
Any help would be appreciated, thanks!

The key idea is to get a grouping identifier for the adjacent rows. The question is: what characteristic of the rows is constant for rows that should be grouped together?
Well, here is one: the number of previous rows (based on id) that have different values in either col1 or col2 is the same for all rows in a group.
You can turn this observation into a measure for each row (using a correlated subquery). The rest is just aggregation:
select min(id) as id, col1, col2, count(*) as NumInGroup
from (select t.*,
(select count(*)
from t t2
where t2.id < t.id and (t2.col1 <> t.col1 or t2.col2 <> t.col2)
) as grp
from t
) t
group by grp, col1, col2;
demo: db-fiddle
Note: This will work well-enough on small amounts of data, but it does not scale particularly well.

Related

how to detect peak of two columns in sql

I have two columns in mysql:
row A B
1 90 80
2 80 57
3 57 5
4 48 30
5 30 15
I need to compare the value of B and the next value of A, how could I detect a peak when B is 5 (row 3) and A is 48 (row 4)? New column can be added to say whether a peak is detected.
The result should be:
row A B peak_detection
1 90 80 0
2 80 57 0
3 57 5 0
4 48 30 1
5 30 15 0
Thank you
In steps:
How big is the difference:
SELECT
A,
B,
LAG(A) over (order by r)-B difference
FROM Table1
Select the max row:
SELECT r
FROM (
SELECT
r,
A,
B,
LAG(A) over (order by r)-B difference
FROM Table1
) t2
ORDER BY difference DESC
LIMIT 1
Add the column peak_detection:
SELECT
A,
B,
IF(Table1.r=t2.r,1,0) peak_detection
FROM Table1
LEFT JOIN (
SELECT r
FROM (
SELECT
r,
A,
B,
LAG(A) over (order by r)-B difference
FROM Table1
) t2
ORDER BY difference DESC
LIMIT 1
) t2 on t2.r=Table1.r
See: dbfiddle
output:
A
B
peak_detection
90
80
0
80
57
0
57
5
1
48
30
0
30
15
0
P.S. code improvement can be done (and might be needed) on the last query, if needed.

How to get permutation of a table?

I have one table with 10 columns. I want to get all the possible permutations. example for table with 3 columns:
col1 col2 col3
10 40 3,
20 6 1,
the permutation table will be:
col1 col2 col3
10 40 3,
10 40 1,
10 6 3,
10 6 1,
20 6 1,
20 6 3,
20 40 3,
20 40 1,
I've tried to do it with CROSS JOIN, but didn't success.
what is the best way to do it?
Thank you!
You can use a cross join:
select c1.col1, c2.col2, c3.col3
from (select distinct col1 from t) c1 cross join
(select distinct col2 from t) c2 cross join
(select distinct col3 from t) c3
order by c1.col1, c2.col2, c3.col3;
Here is a db<>fiddle.

MySQL-select 10 rows with limit on categories column

I have a table in my database which has 3 columns: (id, business_id, name). I need to write a query which selects 10 rows from table which have id greater than a specific value and the point is that not more than 5 rows must be selected for each business_id. how to include this criteria in the query?
so for example if we have these rows in table:
1 A JAD
2 A LPO
3 A LMN
4 A ABC
5 A QWE
6 A WER
7 B TYU
8 B POI
9 B AQZ
10 B UYT
11 C CDE
12 C XYZ
the desired result is (for id>0):
1 A JAD
2 A LPO
3 A LMN
4 A ABC
5 A QWE
7 B TYU
8 B POI
9 B AQZ
10 B UYT
11 C CDE
If you are using MySQL 8+, then ROW_NUMBER can be used here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY business_id ORDER BY id) rn
FROM yourTable
)
SELECT id, business_id, name
FROM cte
WHERE rn <= 5;
In older versions of MySQL, you can use:
select t.*
from t
where id > #id and
id < any (select t2.id
from t t2
where t2.business_id = t.business_id
order by id asc
limit 1 offset 4
)
limit 10;
The any is to handle the case where a business has fewer than four rows.

select rows related with a column

I have table like this;
col1 col2 col3 week
a b c 21
a f g 22
c d e 23
a e f 24
f g h 25
a c f 26
f b e 27
I want to count rows those including 'a' with 1 week difference and 2 weeks and so on.For example;
2 times with 1 week difference, 1 times with 0 difference.Like;
week diff. count
0 1
1 2
2 0
an so on.
Thanks and i tried to be clear with my poor English.
I'm not sure I understand the problem. But, supposing that:
You want to count rows with 'a' in any column (col1, col2, col3).
When you say "2 times with 1 week difference", it's 2 times because 'a' appears in 2 consecutive weeks: 21 and 22.
Same way, there would be 3 rows (so, 3 times) with "2 week difference": rows with week column equal to 22, 24, 26
Then, the following query could be helpful:
SELECT
ABS(t2.week - t1.week) AS week_difference,
COUNT(DISTINCT t1.week) AS count
FROM
temp t1, temp t2
WHERE
((t1.col1 = 'a' OR t1.col2 = 'a' OR t1.col3 = 'a')
AND (t2.col1 = 'a' OR t2.col2 = 'a' OR t2.col3 = 'a'))
AND ABS(t2.week - t1.week) <= 2
GROUP BY
week_difference
ORDER BY
week_difference

how can you eliminate permutations between columns in MySQL

i have table columns one (idprocess) point to columns two (idporcess1) and point to columns tree (idprocess2).
id idprocess idporcess1 idprocess2
1 15 16 17 <== A
2 15 16 19 <== B
3 15 20 23
4 14 16 17
6 16 15 80 <== C
7 17 15 49 <== D
8 23 16 20 <== E
I need a SQL query that returns this: row c and row D, so with number idprocess(16) and idprocess(17 )
because row c : idprocess(16) references again ipdprocess1(15)
because row c : idprocess(17 ) references agin ipdprocess1(15)
please help
i want only to eleminate circular referencial in tree
If you are happy to find rows where the first two columns are permutated, this will do the job:
SELECT *
FROM my_tbl t
WHERE EXISTS (SELECT 1 FROM my_tbl t1 WHERE t1.idprocess = t.idprocess1 AND t1.idprocess1 = t.idprocess)
ORDER BY t.id;
Alternative interpretation:
If you want all rows where idprocess1 has been listed in idprocess before (before = smaller id), then you can:
SELECT *
FROM my_tbl t
WHERE EXISTS (SELECT 1 FROM my_tbl t1 WHERE t1.id < t.id AND t1.idprocess = t.idprocess1)
ORDER BY t.id;
You wouldn't call that "permutation", though.
The question is a bit ambiguous but I tried to understand it on my own and prepared the following query:
SELECT *
FROM TEMP
where C2 IN ( Select C2 FROM TEMP group by C2 having count(C2) > 1 )
OR C3 IN ( Select C3 FROM TEMP group by C3 having count(C3) > 1 )