Select multiple tables in mysql - mysql

I need to make the following query:
I have 4 tables, the first is the main, in which with the 'id' is foreign in the other 3 tables. I need to get the date and description of each of the tables where it presents the id_tabla1. In some tables I have more records than in the other.
Is it possible to relate these tables?
Table 1 main
id_table1
Name
Table 2
id_table2
date
description
fk_table1
Table 3
id_table3
date
description
fk_table1
Table 4
id_table4
date
description
fk_table1
I want to get something like this:

This type of operation is a bit of a pain in MySQL. In fact, the result is not particularly "relational", because each column is a separate list. You can't do a join because there is no join key.
You can generate one in MySQL using variables and then use aggregation. Here is an example with two tables:
select id_table1,
max(t2_date) as t2_date,
max(t2_desc) as t2_desc,
max(t3_date) as t3_date,
max(t3_desc) as t3_desc
from ((select id_table1, NULL as t2_date, NULL as t2_desc, NULL as t3_date, NULL as t3_desc, 1 as rn
from table1 t1
) t1 union all
(select fk_table1, date as t2_date, description as t2_desc, NULL as t3_date, NULL as t3_desc,
(#rn1 := if(#fk1 = fk_table1, #rn1 + 1,
if(#fk1 := fk_table1, 1, 1)
)
) as rn
from table1 t1 cross join
(select #rn1 := 0, #fk1 := 0) params
order by fk_table1, date
) t1 union all
(select fk_table1, NULL, NULL, date as t3_date, description as t3_desc
(#rn2 := if(#fk2 = fk_table1, #rn2 + 1,
if(#fk2 := fk_table1, 1, 1)
)
) as rn
from table1 t1 cross join
(select #rn2 := 0, #fk2 := 0) params
order by fk_table1, date
)
) t
group by id_table1, rn;

Related

Sum the column while next value of rows is not null

I have a MySQL table called agent_log like picture 1. I want output like picture 2.
That means, wait_sec will be sum with next rows while a new uniqueid has come. When come a new uniqueid then again it will be sum with next wait_sec while next uniqueid are null.
Please see the attached images for clear the concept.
Picture 1/My Table
Picture 2/Expected output
Solution 1
select max(uniqueid), sum(wait_sec)
from (
select *, (select count(uniqueid) from agent_log a2 where a2.event_time < a1.event_time) gg
from agent_log a1
) as a
group by gg
Solution 2
select uniqueid, wait_total
from (
select a.*,
if(#prev_id is null, #wait_tot := #wait_tot + a.wait_sec, #wait_tot := a.wait_sec) AS wait_total,
#prev_id := a.uniqueid AS prev_id
from ( select #prev_id := NULL, #wait_tot := 0 ) i
join ( select * from agent_log order by event_time ) a
)a
where uniqueid is not null

MySQL behaviour when using ANY_VALUE multiple times

I want to get a random row for each group when using GROUP BY in MySQL 5.7. The most clean way to do it from my research is doing something like this:
SELECT ANY_VALUE(column_1), ANY_VALUE(column_2), ..., ANY_VALUE(column_n)
FROM table
GROUP BY column
Since there is no syntax for something like ANY_VALUE(*) or ANY_VALUE(column_1, column2, ..., column_n) I am left confused if with the above query each value can come from a different row, or if all ANY_VALUE fields will come from the same row.
If you want a random row, use row_number():
select t.*
from (select t.*,
row_number() over (partition by column order by rand()) as seqnum
from t
) t
where seqnum = 1;
I am guessing that this is also faster than group by, but you can check if that is the case.
In MySQL 5.7, you can use variables:
select t.*
from (select t.*,
(#rn := if(#c = column, #rn + 1,
if(#c := column, 1, 1)
)
) as rn
from (select t.* from t order by column, rand) t cross join
(select #c := '', #rn := 0) params
) t
where rn = 1;
Assuming the following schema and sample data:
create table tbl(
id int auto_increment primary key,
grp int not null,
val int not null,
index (grp)
);
insert into tbl (grp, val) values (1, 1);
insert into tbl (grp, val) values (1, 2);
insert into tbl (grp, val) values (1, 3);
insert into tbl (grp, val) values (2, 1);
insert into tbl (grp, val) values (2, 2);
Get distinct groups in a derived table (or use the base table for groups, if you have). Get a random primary key in a subquery in SELECT clause with ORDER BY rand() LIMIT 1. Then join the result as a derived table with the base table.
select t.*
from (
select (
select id
from tbl t
where t.grp = g.grp
order by rand()
limit 1
) as id
from (select distinct grp from tbl) g
) r
join tbl t using (id);
Result would be something like
| id | grp | val |
| --- | --- | --- |
| 2 | 1 | 2 |
| 4 | 2 | 1 |
View on DB Fiddle

MySQL: How to ORDER BY and SET ids?

I already googled but couldn't find a solution.
I have two columns called order_id and name. I want to ORDER BY name and then SET ascending order_id.
Like this:
order_id name
1 Arya
2 Herbert
3 Paul
4 Peter
5 Tiffany
My id column is int(4) and by default value is 0. It's not PRIMARY or UNIQUE. (It'a also not the main id. Main id is of course PRIMARY.
How can I do this with SQL?
You could use ROW_NUMBER(MySQL 8.0+):
SELECT name, ROW_NUMBER() OVER(ORDER BY name) AS rn
FROM tab
ORDER BY rn;
Update:
UPDATE tab
SET order_id = (SELECT rn FROM (SELECT name,ROW_NUMBER() OVER(ORDER BY name) AS rn
FROM tab)s
WHERE s.name = tab.name); -- assuming that name is UNIQUE
DBFidde Demo
For versions < 8.0 you can use this:
select #rn := 0;
UPDATE tbl T1
JOIN (select #rn := #rn + 1 rn, `name` from tbl order by `name`) T2
ON T1.`name` = T2.`name`
SET T1.order_id = T2.rn
Demo
Useful article related to your problem: MySQL UPDATE JOIN
As your mysql version is below 8.0 so you have to manually generate orderid
below can help you
select t.*,
#rownum := #rownum + 1 AS order_id from
(
select * from
tab o order by name asc
) as t , (SELECT #rownum := 0) r
http://www.sqlfiddle.com/#!9/ae3fda/3

Find all NULL values and set them to lowest unused number using MySQL query

I want to find all NULL values in column parameter_id and set them to lowest unused parameter_id.
I have query which will find lowest unused parameter_id, I also know how to get list of NULL values.
SELECT MIN(t1.parameter_id)+1 FROM table AS t1 WHERE NOT EXISTS (SELECT * FROM table AS t2 WHERE t2.parameter_id = t1.parameter_id+1)
I can get list of all rows with parameter_id=NULL, then make query to find current lowest unused parameter_id and then update parameter_id to that lowest unused number. Since table has 50.000 rows, this approach would create thousands of queries (50.000 * 2 per row).
Is there way to run "single query" which will find all parameter_id=NULL and update them all to current lowest unused parameter_id?
Here is table decrtiption (MySQL 5.5):
id (INT) primary key, auto_increment
parameter_id (INT) default NULL
Sample data:
# id, parameter_id
1, NULL
2, 1
3, NULL
4, 5
5, 3
Desired result:
# id, parameter_id
1, 2
2, 1
3, 4
4, 5
5, 3
EDIT:
I distilled what I want to single query. I simply need to run this query until there is 0 rows affected by UPDATE.
UPDATE `table`
SET parameter_id=
(SELECT *
FROM
(SELECT MIN(t1.parameter_id)+1
FROM `table` AS t1
WHERE NOT EXISTS
(SELECT *
FROM `table` AS t2
WHERE t2.parameter_id = t1.parameter_id+1)) AS t4)
WHERE parameter_id IS NULL LIMIT 1
The following enumerates the unused parameter ids:
select t.*, (#rn := #rn + 1) as seqnum
from table t cross join
(select #rn := 0) params
where not exists (select 1 from table t2 where t2.parameter_id = t.id)
order by t.id;
(You might want to put this in a temporary table with an index on seqnum for the subsequent query.)
The problem is getting a join key for the update. Here is a bit of a kludge: I'm going to add a column, enumerate it, and then drop it:
alter table `table` add column null_seqnum;
update `table` t cross join (select #rn1 := 0) params
set null_seqnum = (#rn1 := #rn1 + 1)
where parameter_id is null;
update `table` t join
(select t.*, (#rn := #rn + 1) as seqnum
from `table` t cross join
(select #rn := 0) params
where not exists (select 1 from `table` t2 where t2.parameter_id = t.id)
order by t.id
) tnull
on t.null_seqnum = tnull.seqnum
set t.parameter_id = tnull.id;
alter table `table` drop column null_seqnum;

How to select certain numbers of groups in MySQL?

I have the table with data:
And for this table I need to create pegination by productId column. I know about LIMIT N,M, but it works with rows and not with groups. For examle for my table with pegination = 2 I expect to retrieve all 9 records with productId = 1 and 2 (the number of groups is 2).
So how to create pegination by numbers of groups ?
I will be very thankfull for answers with example.
One way to do pagination by groups is to assign a product sequence to the query. Using variables, this requires a subquery:
select t.*
from (select t.*,
(#rn := if(#p = productid, #rn + 1,
if(#rn := productid, 1, 1)
)
) as rn
from table t cross join
(select #rn := 0, #p := -1) vars
order by t.productid
) t
where rn between X and Y;
With an index on t(productid), you can also do this with a subquery. The condition can then go in a having clause:
select t.*,
(select count(distinct productid)
from t t2
where t2.productid <= t.productid)
) as pno
from t
having pno between X and Y;
Try this:
select * from
(select * from <your table> where <your condition> group by <with your group>)
LIMIT number;