Why LEFT OUTER JOIN reduces rows from left table? - mysql

Just want to show all data in table A and LEFT JOIN table B with coorelate subquery but fail to get all data in table A
SELECT a.id FROM tableA a
LEFT JOIN tableB b1 ON a.id = b1.id
WHERE date = (SELECT MAX(date) FROM tableB b2 WHERE b1.id= b2.id)
tableA
id
======
1001
1002
1003
1004
tableB
id date
=============
1001 20160101
1001 20160102
1003 20160102
1003 20160105
Expected Result
id date
===============
1001 20160102
1002 NULL
1003 20160105
1004 NULL
Engine Return
id date
=============
1001 20160102
1003 20160105

What I would do is a left join on a subselect, that only contains the max date per id like this:
SELECT a.id, b.maxdate FROM tableA a
LEFT JOIN (SELECT id, MAX(date) AS 'maxdate' FROM tableB2 GROUP BY id) b ON a.id = b.id
This should also be quicker, since the select for the join will only be executed once while the select in a where clause will be executed for each row.

update your query to be:
SELECT a.id, b1.date FROM tableA a
LEFT outer JOIN tableB b1 ON a.id = b1.id
WHERE date = (SELECT MAX(date) FROM tableB b2 WHERE b1.id= b2.id) or date is null

The where clause applies on the joined dataset, therefore your where condition removes those records from the resultset, that do not match the criteria.
I would move your subquery to the from clause:
SELECT a.id FROM tableA a
LEFT JOIN (SELECT MAX(date) as mdate, id FROM tableB GROUP BY id) b1 ON a.id = b1.id

Related

How to left join when only matched one record from right table

I want to know How to left join when only matched one record from right table.
For example,
tableA
id
value
1
34
2
42
3
60
tableB
id
value
tableA_id
1
20
1
2
31
1
3
50
2
I want to get result like below using left outer join.
tableA_id
tableA_value
tableB_value
1
34
null
2
42
50
3
60
null
tableB_value of first row is null, because tableA.id = tableB.tableA_id matches multiple records.
how to solve it ?
Thanks.
You can make use of COUNT() as an analytic function to keep track of how many times a tableA_id occurs in the A table:
SELECT a.id AS tableA_id, a.value AS tableA_value, b.value AS tableB_value
FROM tableA a
LEFT JOIN
(
SELECT *, COUNT(*) OVER (PARTITION BY tableA_id) cnt
FROM tableB
) b
ON a.id = b.tableA_id AND b.cnt = 1
ORDER BY a.id;
Demo
You can do this using aggregation on the b table as well:
SELECT a.id AS tableA_id, a.value AS tableA_value, b.value AS tableB_value
FROM tableA a LEFT JOIN
(SELECT tableA_id, MAX(value) as value
FROM tableB
GROUP BY tableA_id
HAVING COUNT(*) = 1
) b
ON a.id = b.tableA_id
ORDER BY a.id;
This works because if there is only one row in B for a given id, then MAX() returns the value on that row.

Left Join query not working

I have 2 tables.
Table 1:
ID Name Age PhoneNumber
12 Joe 25 873827382
23 Bob 28 928398233
34 Jane 23 237828883
Table 2:
ID Agent QuantitySold
12 A1 100
23 B1 300
12 C1 600
34 A2 400
34 B1 800
23 B2 900
I want to show all the details of the employees who have never sold a quantity not equal to 800.
SELECT a.ID, a.Name, a.Age, a.PhoneNumber
FROM table1 a LEFT JOIN table2 b
ON a.ID= b.ID AND b.quantity <> 800
I want a result set that doesn't have ID 34 in it. But I cant seem to achieve that. Any help?
You need to change your Left Join to Inner Join.
Left Join will bring all the rows from table1 even though he never made a sales. I will do this using Exists.
SELECT a.ID,
a.Name,
a.Age,
a.PhoneNumber
FROM table1 a
WHERE EXISTS (SELECT 1
FROM table2 b
WHERE a.ID = b.ID
AND b.quantity <> 800)
You can use NOT EXISTS without any of the JOINs:
SELECT a.ID
, a.Name
, a.Age
, a.PhoneNumber
FROM table1 a
WHERE NOT EXISTS (SELECT * FROM table2 WHERE ID = a.ID AND QuantitySold = 800)
By the way, the column name is QuantitySold, not quantity.
JSFiddle
This is what finally worked.
SELECT a.ID
, a.Name
, a.Age
, a.PhoneNumber
FROM table1 a
WHERE a.ID NOT IN (SELECT ID FROM table2 QuantitySold = 800);
Why you are using Left Join. Use inner join rather. Something like this:-
SELECT a.ID, a.Name, a.Age, a.PhoneNumber, SUM(b.quantity)
FROM table1 a JOIN table2 b
ON a.ID= b.ID
GROUP BY b.Agent
HAVING SUM(b.quantity) <> 800

All conditional data required in mysql

I have three table a,b,c having id common between them.
Table a:-
id name value
1 a 4
2 v 6
Table b:-
id abc
2 54
3 56
Table c:-
id bcd
1 54
3 34
Now what i want is what ever is id in where condition, data comes from all tables.
Please advice me how to do that.
Expected Result-
if query is
select * from a left join b on a.id=b.id left join c on a.id=c.id where b.id=3
id name value bcd abc
3 NULL NULL 34 56
if query is
select * from a left join b on a.id=b.id left join c on a.id=c.id where a.id=1
id name value bcd abc
3 a 4 54 NULL
What about this approach to the problem? :)
SELECT
z.id,
a.name,
a.value,
c.bcd,
b.abc
FROM
(
SELECT
DISTINCT y.id id
FROM
(
SELECT id FROM a
UNION ALL
SELECT id FROM b
UNION ALL
SELECT id FROM c
) y
) z
LEFT JOIN a ON z.id = a.id
LEFT JOIN b ON z.id = b.id
LEFT JOIN c ON z.id = c.id
where z.id = 3
sql fiddle
This way you just need to give the query the number not caring about which tables it exists in.
It's depends on what you are setting in WHERE condition. If you are setting WHERE b.ID = 3 then you need to join other tables with B like this:
SELECT A.ID AS A_ID,A.Name, A.value
,B.Id as B_ID,B.abc
,C.id AS C_ID, c.bcd
FROM b
LEFT JOIN a ON a.id = b.id
LEFT JOIN c ON a.id = c.id
WHERE b.id=3;
This is happens because b.ID = 3 is not in Table A and Table C is joined with Table A.
If you set Table A.ID = 1 then you have to join other tables with A using LEFT JOIN like this:
SELECT A.ID AS A_ID,A.Name, A.value
,B.Id as B_ID,B.abc
,C.id AS C_ID, c.bcd
FROM A
LEFT JOIN B ON a.id = b.id
LEFT JOIN c ON a.id = c.id
WHERE A.id=1;
See this SQLFiddle
This is technically impossible, when you are using ID in where how can you get data in case there Id not present in any of the perticular table, you are changing the logic of where ;).
But what you can do is
SELECT * FROM
(SELECT AID AS ID,NAME,VALUE FROM A
UNION
SELECT BID as ID,NAME,NULL AS VALUE FROM B
UNION
SELECT CID as ID,NAME ,NULL AS VALUE FROM C)
WHERE ID =''
Hope this helps
else please clarify. what you want.
Regards
Ashutosh Arya
I will try to guess, even though I barely find an explanation to the expected result:
SELECT
b.id,
a.name,
a.value,
c.bcd,
b.abc
FROM
b
INNER JOIN c ON b.id = c.id
LEFT JOIN a ON b.id = a.id
sql fiddle

MySQL Multiple JOIN query

I have 3 tables:
Table A:
id int
value varchar
Table B:
id int
a_id default null
Table C:
id int
a_id not null
And I need to group number of B rows and C rows by A.value:
+---------+----------------------+----------------------+
| A.value | COUNT(DISTINCT B.id) | COUNT(DISTINCT C.id) |
+---------+----------------------+----------------------+
| NULL | 100 | 0 |
| 1 | 543 | 324 |
...
The problem is that the B table has a nullable foreign key while C.a_id can not be null.
So after hour of trying I can't get the right query. Either C.a_id are losing or B.a_id.
What is the right way to get it?
Because the values are pretty large, it might be better to do the calculations in subqueries:
select a.name, Distinct_B, Distinct_C
from (select distinct a.name from TableA a) a left outer join
(select a.value, count(distinct b.id) as Distinct_B
from TableA a join
TableB b
on a.id = b.a_id
group by a.value
) b
on a.value = b.value left outer join
(select a.value, count(distinct c.id) as distinct_C
from TableA a join
TableC c
on a.id = c.a_id
) c
on a.value = c.value
This looks more complicated, but it does not require a partial cartesian product within each a.value. Also, it can be simplified, if there are no multiple a.values allowed.
If you want to keep all B values that have "NULL" a_id by assigning them a NULL a.value, then use this subquery instead:
select a.value, sum(Distinct_B), sum(Distinct_C)
from ((select distinct a.name, 0 as Distinct_B, 0 as Distinct_C
from TableA a
) union all
(select a.value, count(distinct b.id) as Distinct_B, 0 as Distinct_C
from TableB b left outer join
TableA a
on a.id = b.a_id
group by a.value
) union all
(select a.value, 0 as Distinct_B, count(distinct c.id) as distinct_C
from TableC c left outer join
TableA a
on a.id = c.a_id
)
) t
group by a.value
This uses aggregation instead of a join to bring the values together.

How to select last date in 2 record in Mysql

How to select last date in 2 records in Mysql ?
TABLE A
SID NAME Sex
1 Jam M
2 Da F
TABLE B
ID Title SID Date
1 A 1 2012-07-31 09:57:10
2 NULL 1 2012-07-31 09:57:13
3 A 2 2012-07-31 10:10:13
4 NULL 2 2012-07-31 10:57:13
I want to inner join those two tables,
but select only one record only of Table B(distinct of SID) where title not null then show the
biggest Date of title is null field.
Result want the biggest Date of Null title:
ID Name Title SID Date
1 Jam A 1 **2012-07-31 09:57:13**
2 DA A 2 **2012-07-31 10:57:13**
How to do that ?
SELECT b.ID, a.NAME, b.Title, b.SID, b.Datea
from tablea a left outer join
(( SELECT sid, MAX(datea) AS latest
FROM tableb
where title is not null
GROUP BY sid) AS dt
INNER JOIN tableb b ON b.sid= dt.sid and b.datea=dt.latest )
on a.sid=b.sid
I think something like this will work for you:
SELECT b.ID, a.NAME, b.Title, b.SID, b.Date
FROM TABLEA a
INNER JOIN (SELECT SID, IFNULL(Title, "") AS Title,
MAX(IF(Title IS NULL, Date, NULL)) Date
FROM TABLEB GROUP BY SID) b
ON a.SID = b,SID;
Try my code (it works):
SELECT b.id, b.title, b.sid, b.date
FROM table_b as b
JOIN table_a as a ON a.sid = b.sid
WHERE b.id in (SELECT MAX(id) FROM table_b GROUP BY sid)