Select all queries with reference id in a chain - mysql

I have this table which I would like to store a chain of records.
CREATE TABLE table_name (
id INT,
unique_id varchar,
reference_id varchar,
);
I want to implement SQL query for MariDB which prints all records by id with all records with reference_id. Something like this:
| id | unique_id | reference_id | | |
|----|-----------|--------------|---|---|
| 43 | 55544 | | | |
| 45 | 45454 | 43 | | |
| 66 | 55655 | 45 | | |
| 78 | 88877 | 66 | | |
| 99 | 454 | 33 | | |
I would like when I select record 66 to get all up and down transactions because each other are using id which points to them. How I can implement this using Recursive CTE? Is there a better way?
Expected result for record with unique_id 66:
| id | unique_id | reference_id | | |
|----|-----------|--------------|---|---|
| 43 | 55544 | | | |
| 45 | 45454 | 43 | | |
| 66 | 55655 | 45 | | |
| 78 | 88877 | 66 | | |
I tried this but above rows are not printed.
select #ref:=id as id, unique_id, reference_id
from mytable
join (select #ref:=id from mytable WHERE reference_id=#ref or id = 66)tmp
where reference_id=#ref
Demo on DB Fiddle
Can you give me hand to find a solution?
EDIT: Attempt with CTE:
with recursive cte as (
select t.*
from mytable
where t.id = 66
union all
select t.*
from cte join
mytable t
on cte.id = t.reference_id
)
select *
from cte;
I get error Unknown table 't'

I'm not familiar with recursive CTE. You can try the below query.
select t.id, t.unique_id, #uid := t.reference_id reference_id
from (select * from mytable order by id desc) t
join (select #uid := 66) tmp
where t.id = #uid or reference_id=66

Related

How to select all columns of a table with unique combination of just some of them in MySQL?

I have a MySQL table named "Products" with the following structure:
id | name | variety | t_min | t_max | entity
====================================================
1 | hake | salmo salar | -5.27 | 10.3 | entity1
2 | salmon | null | -2.45 | 12.9 | entity1
3 | cod | gadus morhua | -4.98 | 11.98 | entity1
4 | hake | salmo salar | -7.87 | 9.35 | entity1
5 | hake | salmo salar | -2.76 | 8.46 | entity1
The desired result I would want is:
id | name | variety | t_min | t_max | entity
====================================================
1 | hake | salmo salar | -5.27 | 10.3 | entity1
2 | salmon | null | -2.45 | 12.9 | entity1
3 | cod | gadus morhua | -4.98 | 11.98 | entity1
I want to select all the columns of the table but avoid repeating rows that have the same name+variety in this case. Just using DISTINCT clause doesn't work because if I use it I just can select the columns I want to be unique, so how can I do it?
Use window function
select *
from (
select *, row_number() over(partition by name, variety order by id) rn
from products
) r
where r.rn = 1
order by r.id
try
select * from ( select * , ROW_NUMBER() OVER(PARTITION BY name ORDER
BY id) AS row from Products ) as a where row = 1
hopefully it will give you the unique data.

sort data by specific order sequence (mysql)

So, let say I have this data
id | value | group
1 | 100 | A
2 | 120 | A
3 | 150 | B
4 | 170 | B
I want to sort it so it become like this
id | value | group
1 | 100 | A
3 | 150 | B
2 | 120 | A
4 | 170 | B
there will be more group than that, so if I the data ordered the group like (A,C,B,D,B,C,A), it will become (A,B,C,D,A,B,C)
You can add a counter column to the table, which will be used to sort the table:
select t.id, t.value, t.`group`
from (
select t.id, t.value, t.`group`,
(select count(*) from tablename
where `group` = t.`group` and id < t.id) counter
from tablename t
) t
order by t.counter, t.`group`
See the demo.
Results:
| id | value | group |
| --- | ----- | ----- |
| 1 | 100 | A |
| 3 | 150 | B |
| 2 | 120 | A |
| 4 | 170 | B |
You can approach this as
SELECT *
FROM `tablename`
ORDER BY
row_number() OVER (PARTITION BY `group` ORDER BY `group`), `group`

HAVING COUNT receiving other COUNT value

I'm working with a select in two different tables that should be match by group reference id, like:
Table 1 and table 2:
+-----+-----+------------+ +-----+------+
| gid | tid | created | | gid | nid |
+-----+-----+------------+ +-----+------+
| 0 | 816 | 1480002041 | | 0 | 1123 |
| 1 | 731 | 1480003932 | | 0 | 1124 |
| 1 | 736 | 1480003932 | | 1 | 1125 |
| 2 | 746 | 1480003932 | | 1 | 1126 |
+-----+-----+------------+ | 1 | 1123 |
| 2 | 1124 |
| 1 | 1129 |
+-----+------+
I need to get nid values from table 2 that have a exactly group match with the group on table 1. The reference to search in table 1 is tid.
I believe that the SQL would be something like that:
SELECT t1.nid
FROM table1 t1
INNER JOIN
(
SELECT gid
FROM table2
WHERE tid IN (731, 736, 746, 751)
GROUP BY gid
HAVING COUNT(DISTINCT tid) = 4
) t2 ON t1.gid = t2.gid;
But how can I get the exactly count to replace hard coded number 4?
SELECT t2.nid
FROM table1 t1
INNER JOIN
table2 t2
ON t1.gid = t2.gid;
WHERE t2.tid IN (731, 736, 746, 751)
GROUP BY t2.gid

mysql advanced order by query

I have a table like this in MySQL:
+-----+------+
| id | type |
+-----+------+
| 149 | 8 |
| 150 | 7 |
| 151 | 8 |
| 152 | 7 |
| 153 | 5 |
| 154 | 6 |
| 155 | 3 |
| 156 | 2 |
| 157 | 4 |
| 158 | 2 |
| 159 | 1 |
| 160 | 0 |
+-----+------+
I would like to sort this table and receive results like this:
+-----+------+
| id | type |
+-----+------+
| 151 | 8 |
| 152 | 7 |
| 154 | 6 |
| 153 | 5 |
| 157 | 4 |
| 155 | 3 |
| 158 | 2 |
| 159 | 1 |
| 160 | 0 |
| 149 | 8 |
| 150 | 7 |
| 156 | 2 |
+-----+------+
As further explanation, I want to sort type column like continues count down like this : 8,7,6,5,4,3,2,1,0,8,7,6,5,4,3,2,1,0,8,7,...
Is it possible to sort table like that? or achieve that result by procedures or something else?
SELECT id, TYPE FROM (
SELECT id, TYPE,
IF(#myvar = 0 OR #myvar = TYPE, #counter := #counter + 1, #counter := 1) sequence,
#myvar := TYPE FROM mytable
JOIN (SELECT #myvar := 0, #counter := 0 ) a
ORDER BY TYPE DESC, id) b
ORDER BY sequence, TYPE DESC, id
This query will work for any level.
Put an outer query if necessary to fetch only relevant fields.
Checkout this SqlFiddle
This will work only if frequency of type is two.
Write following code in procedure:
drop temporary table if exists tmp;
create temporary table tmp
select min(id) as min_id ,max(id) as max_id from table_name group by type;
select * from table_name where id in( select max_id from tmp) order by type
union all
select * from table_name where id in(select min_id from tmp) order by type;
Try this query
select id,type from(
SELECT a.id, a.Type, count(*) as row_number FROM test a
JOIN test b ON a.type = b.type AND a.id >= b.id
GROUP BY a.Type, a.id) a
order by row_number

Get MAX row for GROUP in MySQL

I have the following data:
+---------+----------+----------+--------+
| id | someId | number | data |
+---------+----------+----------+--------+
| 27 | 123 | 1 | abcde1 |
| 28 | 123 | 3 | abcde2 |
| 29 | 123 | 1 | abcde3 |
| 30 | 123 | 5 | abcde4 |
| 31 | 124 | 4 | abcde1 |
| 32 | 124 | 8 | abcde2 |
| 33 | 124 | 1 | abcde3 |
| 34 | 124 | 2 | abcde4 |
| 35 | 123 | 16 | abcde1 |
| 245 | 123 | 3 | abcde2 |
| 250 | 125 | 0 | abcde3 |
| 251 | 125 | 1 | abcde4 |
| 252 | 125 | 7 | abcde1 |
| 264 | 125 | 0 | abcde2 |
| 294 | 123 | 0 | abcde3 |
| 295 | 126 | 0 | abcde4 |
| 296 | 126 | 0 | abcde1 |
| 376 | 126 | 0 | abcde2 |
+---------+----------+----------+--------+
And I want to get a MySQL query that gets me the data of the row with the highest number for each someId. Note that id is unique, but number isn't
SELECT someid, highest_number, data
FROM test_1
INNER JOIN (SELECT someid sid, max(number) highest_number
FROM test_1
GROUP BY someid) t
ON (someid=sid and number=highest_number)
Unfortunately it is not look quite efficient. In Oracle it could be possible to user OVER clause without subqueries, but MySQL…
Update 1
If there are several instances of highest number this will returs also several data for each pair of someid and number.
To get the only row per each someid we should preaggregate the source table to make someid and number pairs unique (see t1 subquery)
SELECT someid, highest_number, data
FROM
(SELECT someid, number, MIN(data) data
FROM test_1
GROUP BY
someid, number) t1
INNER JOIN
(SELECT someid sid, max(number) highest_number
FROM test_1
GROUP BY someid) t2
ON (someid=sid and number=highest_number)
Update 2
It is possible to simplify previous solution
SELECT someid,highest_nuimber,
(select min(data)
from test_1
where someid=t1.someid and number=highest_nuimber)
FROM
(SELECT someid, max(number) highest_nuimber
FROM test_1
GROUP BY someid) t1
If we materialize unique pairs of someid and number than it is possible to use correlated subquery. Unlike a JOIN it would not produce additional rows if highest value of number is repeated several times.
Slight tweak to Naeel's answer but to return just a single data result for any someId even if there's a tie you should add a GROUP BY:
SELECT t1.someid, t1.number, t1.data
FROM Table1 t1
INNER JOIN (SELECT someId sid, max(number) max_number
FROM Table1
GROUP BY someId) t2
ON (someId = sid AND number = max_number)
GROUP BY t1.someId
SQL Fiddle here