outer join in mysql not providing the results - mysql

Hypothetical data -
tbl1 -
id
date
value1
101
2021-01-01
200
101
2021-01-03
400
tbl2 -
id
date
value2
101
2021-01-01
600
101
2021-01-02
900
My expected result is -
id
date
value1
value2
101
2021-01-01
200
600
101
2021-01-02
NaN
900
101
2021-01-03
400
NaN
select * from (select * from tbl1 where id in
(another query)) t1
left join tbl2 as t2 on t1.id = t2.id and t1.date = t2.date
union all
select * from (select * from tbl1 where id in
(another query)) t1
right join tbl2 as t2 on t1.id = t2.id and t1.date = t2.date
where t1.id is null and t1.date is null
I am unable to figure out where am I going wrong.

I think you might be overcomplicating your union query:
SELECT t1.id, t1.date, t1.value1, t2.value2
FROM tbl1 t1
LEFT JOIN tbl2 t2 ON t1.id = t2.id AND t1.date = t2.date
UNION ALL
SELECT t2.id, t2.date, t1.value1, t2.value2
FROM tbl1 t1
RIGHT JOIN tbl2 t2 ON t1.id = t2.id AND t1.date = t2.date
WHERE t1.id IS NULL
ORDER BY id, date;
Demo

Collect all present (id, `date`) pairs then join source data to it:
SELECT id, `date`, tbl1.value1, tbl2.value2
FROM ( SELECT id, `date` FROM tbl1
UNION
SELECT id, `date` FROM tbl2 ) combined
LEFT JOIN tbl1 USING (id, `date`)
LEFT JOIN tbl2 USING (id, `date`);
fiddle
The solution assumes that (id, `date`) is unique over each separate source table. If not then some aggregation must be used (SUM or MAX, depends on the logic).

Related

Mysql - reorder / reset position key

I have a MySQL table with position key (65,000 records). I deleted, updated some rows in the middle of the table. Now I have, for example, something like this in the position 1 - 6 - 2 - 9
id
category
position
1
1
1
2
1
6
3
2
2
4
2
9
I want to reset / reorder the position key
id
category
position
1
1
1
2
1
2
3
2
1
4
2
2
How can I reset position where category = 1
and where category = 2?
Try this:
UPDATE source_table
JOIN ( SELECT id, ROW_NUMBER() OVER (PARTITION BY category ORDER BY position) position
FROM source_table ) subquery USING (id)
SET source_table.position = subquery.position
mysql> SHOW VARIABLES LIKE "%version%"; 5.7.24 – sagittarius
UPDATE source_table
JOIN ( SELECT t1.id, COUNT(t2.id) position
FROM source_table t1
JOIN source_table t2 ON t1.category = t2.category
AND t1.position >= t2.position
GROUP BY t1.id ) subquery USING (id)
SET source_table.position = subquery.position;
fiddle
if position is duplicated everything crashes – sagittarius
UPDATE source_table
JOIN ( SELECT t1.id, COUNT(t2.id) position
FROM source_table t1
JOIN source_table t2 ON t1.category = t2.category
AND ( t1.position > t2.position
OR ( t1.position = t2.position
AND t1.id >= t2.id ))
GROUP BY t1.id ) subquery USING (id)
SET source_table.position = subquery.position;
fiddle
UPDATE source_table t1
INNER JOIN
(
SELECT id,category,position, ROW_NUMBER() OVER (PARTITION BY category
ORDER BY position) position2
FROM source_table
) t2
ON t2.id = t1.id
SET
t1.position = t2.position2
I think this code is easy to understand and apply.

SQL set LIMIT in WHERE IN

I Have table like this:
id user_id date
1 10 2018-12-13
3 11 2018-11-29
4 12 2018-12-05
My Query looks like this:
SELECT * FROM table WHERE IN(10,11,12) AND date > 2018-11-15
Now I get all records fromt table > 2018-11-15 but I need to get first user records.
I get now:
id user_id date
1 10 2018-12-13
2 10 2018-12-01
3 11 2018-11-29
4 12 2018-12-05
5 12 2018-12-06
I need like this:
id user_id date
1 10 2018-12-13
3 11 2018-11-29
4 12 2018-12-05
One approach is to join your table to a subquery which finds the latest records for each user_id:
SELECT
t1.id,
t1.user_id,
t1.date
FROM yourTable t1
INNER JOIN
(
SELECT user_id, MAX(date) AS max_date
FROM yourTable
WHERE user_id IN (10, 11, 12)
GROUP BY user_id
) t2
ON t1.user_id = t2.user_id AND t1.date = t2.max_date
WHERE
t1.user_id IN (10, 11, 12);
To get the results in your question, you need to use grouping and find the minimum id:
SELECT t1.id, t1.user_id, t1.date
FROM table t1
INNER JOIN (SELECT MIN(id) AS min_id
FROM table
WHERE user_id IN(10, 11, 12)
AND date > 2018-11-15
GROUP BY user_id
) t2 ON t1.id = t2.id
WHERE t1.user_id IN (10, 11, 12)
AND date > 2018-11-15;
Maybe a NOT EXISTS could be used for this.
SELECT *
FROM yourtable t1
WHERE user_id IN (10, 11, 12)
AND `date` > '2018-11-15'
AND NOT EXISTS
(
SELECT 1
FROM yourtable t2
WHERE t2.user_id = t1.user_id
AND t2.id < t1.id
AND t2.`date` > '2018-11-15'
);
Test on SQL Fiddle here

Merge tables and keeping all distinct ID values

I have multiple tables to merge and these tables may have different ID values.
For example:
Table 1:
ID Year Month Size1
A 2015 4 10
B 2015 5 20
Table 2:
ID Year Month Size2
A 2015 4 20
C 2015 5 40
Table 3:
ID Year Month Size3
D 2015 6 50
E 2015 7 50
I want the merged table to look like this:
ID Year Month Size1 Size2 Size3
A 2015 4 10 20 NULL
B 2015 5 20 NULL NULL
C 2015 5 NULL 40 NULL
D 2015 6 NULL NULL 50
E 2015 7 NULL NULL 50
I want the output ID column to include all distinct IDs from all the tables.
My guess is that this can be somehow achieved by using Full Outer Join On ID, but I wasn't quite able to produce the desired output format.
Here's another possible query that would give the result you show:
SELECT t.id, t.year, t.month,
SUM(size1) AS size1, SUM(size2) AS size2, SUM(size3) AS size3
FROM (
SELECT id, year, month, size1, NULL AS size2, NULL AS size3 FROM t1
UNION ALL
SELECT id, year, month, NULL, size2, NULL FROM t2
UNION ALL
SELECT id, year, month, NULL, NULL, size3 FROM t3
) AS t
GROUP BY t.id, t.year, t.month;
select t1.id, t1.year, t1.month, t1.size1, t2.size2, t3.size3
from table1 as t1
left outer join table2 as t2 on t1.id = t2.id and t1.year = t2.year and t1.month = t2.month
left outer join table3 as t3 on t1.id = t3.id and t1.year = t3.year and t1.month = t3.month
union
select t3.id, t3.year, t3.month, t1.size1, t2.size2, t3.size3
from table3 as t3
left outer join table1 as t1 on t3.id = t1.id and t3.year = t1.year and t3.month = t1.month
left outer join table2 as t2 on t3.id = t2.id and t3.year = t2.year and t3.month = t2.month

MySQL select 1 row from multiple rows

Please Suggest to get single 0 type row from multiple (0 type rows) and selected row should be just before type 1 row
Emp_tbl (id,type,company_id,created_at)
1,0,121,2015-02-19 18:05
2,0,121,2015-02-19 18:15
3,0,121,2015-02-19 18:17
4,1,121,2015-02-19 19:22
5,2,121,2015-02-19 19:25
6,0,121,2015-02-19 22:05
7,0,121,2015-02-19 22:15
8,0,121,2015-02-19 22:17
9,1,121,2015-02-19 22:22
10,2,121,2015-02-19 22:25
Expected Result
3,0,121,2015-02-19 18:17
4,1,121,2015-02-19 19:22
5,2,121,2015-02-19 19:25
8,0,121,2015-02-19 22:17
9,1,121,2015-02-19 22:22
10,2,121,2015-02-19 22:25
So what you want is the MAX(Id) of the type = 0 rows for each row that has type = 1, where the Id is less. You can join and group to get that:
select max(t0.Id) Id
from Emp_tbl t1
join Emp_tbl t0 on t0.type = 0 and t0.Id < t1.Id
where t1.type = 1
group by t1.Id
The rest is just putting it together:
select *
from Emp_tbl
where type <> 0
union all
select t.*
from Emp_tbl t
join (
select max(t0.Id) Id
from Emp_tbl t1
join Emp_tbl t0 on t0.type = 0 and t0.Id < t1.Id
where t1.type = 1
group by t1.Id
) t0 on t.Id = t0.Id
SQL Fiddle demo

MySQL: Maximum of date(s) columns from multiple tables

I have 4 different tables; each have their own DATETIME independent of each other. What would be the MySQL query to get MAX of all dates in 1 query?
t1: DATE_TIME
t2: DATE_TIME
t3: DATE_TIME
t4: DATE_TIME
Desired result
---------------------------------------------------------
| max_t1_date | max_t2_date | max_t3_date | max_t4_date |
---------------------------------------------------------
Many ways to skin this cat...
SELECT max( t1.a ) AS max_table1date,
max( t2.a ) AS max_table2date,
max( t3.a ) AS max_table3date
FROM table1 t1,
table2 t2,
table3 t3
It's been a while since I used MySQL syntax and I cannot try this at the moment, but this should work:
SELECT
(SELECT MAX(date_time) FROM t1) AS max_t1_date,
(SELECT MAX(date_time) FROM t2) AS max_t2_date,
(SELECT MAX(date_time) FROM t3) AS max_t3_date,
(SELECT MAX(date_time) FROM t4) AS max_t4_date
SELECT t1.MaxDate max_t1_date,
t2.MaxDate max_t2_date,
t3.MaxDate max_t3_date,
t4.MaxDate max_t4_date
FROM (SELECT MAX(DATE_TIME) MaxDate FROM t1) t1
(SELECT MAX(DATE_TIME) MaxDate FROM t2) t2,
(SELECT MAX(DATE_TIME) MaxDate FROM t3) t3,
(SELECT MAX(DATE_TIME) MaxDate FROM t4) t4