Join two tables without mixing rows - mysql

I want to join 2 tables and for each joined result I need a separate row, but the rows of my query result are somehow mixed:
Schema + Data:
My Query:
SELECT Table_A.id,
Table_B.id,
Table_C.id
FROM Table_A
LEFT JOIN Table_B
ON Table_B.id_a = Table_A.id
LEFT JOIN Table_C
ON Table_C.id_a = Table_A.id
The Result:
What I want (3 separate rows - separated by the join-tables' id-column):
Q: What am I doing wrong?
=> You could put it in that way: I need all rows of where id_a is 1 + table_a.id=1. Maybe JOIN is the wrong approach here..?

You need INNER JOIN UNION :
SELECT A.id A_Id, B.id B_Id, ''c_id
FROM Table_A A
INNER JOIN Table_B B ON B.id_a = A.id
UNION ALL
SELECT A.id A_Id, '' B_Id, c.id c_id
FROM Table_A A
INNER JOIN Table_C C ON A.id = C.id_a

Related

How do I join the most recent row from one table to another and include all rows if there isn't yet a date row?

I'd like to bring in just the most recent date row along with other fields from Table B that would include all values for multiple columns in Table A, even if there is no value in Table B.
The following query works, but only returns values that exist in both Table A AND in Table B. How do I include all of A and the most recent date row of B?
Many Thanks!
SELECT A.person_id,
A.second_field,
B.create_timestamp,
B.second_field
FROM (
SELECT B.person_id, max(B.create_timestamp) as create_timestamp
FROM Table_B B
GROUP BY B.person_id
) BMaxDate
LEFT JOIN Table_B B
ON BMaxDate.person_id = B.person_id AND
BMaxDate.create_timestamp = B.create_timestamp
LEFT JOIN Table_A A ON BMaxDate.person_id = A.person_id
You have to use Table_A as the first table in the LEFT JOIN operation chain:
SELECT A.person_id,
A.second_field,
B.create_timestamp,
B.second_field
FROM Table_A AS A
LEFT JOIN (
SELECT B.person_id, max(B.create_timestamp) as create_timestamp
FROM Table_B B
GROUP BY B.person_id
) AS BMaxDate ON BMaxDate.person_id = A.person_id
LEFT JOIN Table_B AS B
ON BMaxDate.person_id = B.person_id AND
BMaxDate.create_timestamp = B.create_timestamp
If you want all from table_A and use a left join you have to put table_A first.
And for Sql Server you can use the with clause for more readable sub query. Mysql doesn't support the with clause.
With(
SELECT B.person_id, max(B.create_timestamp) as create_timestamp
FROM Table_B B
GROUP BY B.person_id
) AS BMaxDate
SELECT A.person_id,
A.second_field,
B.create_timestamp,
B.second_field
FROM Table_A AS A
LEFT JOIN BMaxDate ON BMaxDate.person_id = A.person_id
LEFT JOIN Table_B AS B ON BMaxDate.person_id = B.person_id
AND BMaxDate.create_timestamp = B.create_timestamp

MySql strange performance

First of all, for example I have 3 table A, B, C. Table A has relation with table B and table has relation with table C. I want to get SUM of some field from table A which depends on some fields from table C.
Table A has > 300k rows, Table B has > 4k rows, Table C has ~ 100 rows
My query looks like that:
SELECT SUM(a.hours) AS total
FROM table_a a
LEFT JOIN table_b b
ON a.table_b_id = b.id
LEFT JOIN table_c c
ON b.table_c_id = c.id
WHERE a.customer_id = 1
AND c.title IN ('Title D','Title E')
Query execution time is ~7 sec, it's very slow. But execution time of query like below is ~0.0 sec.
SELECT a.hours
FROM table_a a
LEFT JOIN table_b b
ON a.table_b_id = b.id
LEFT JOIN table_c c
ON b.table_c_id = c.id
WHERE a.customer_id = 1
AND c.title IN ('Title D','Title E')
Why SUM is so slow? what should I do?
Move your condition to ON clause for related table:
SELECT SUM(a.hours) AS total
FROM table_a a
LEFT JOIN table_b b
ON a.table_b_id = b.id
LEFT JOIN table_c c
ON b.table_c_id = c.id
AND c.title IN ('Title D','Title E')
WHERE a.customer_id = 1
EDIT 1 According to #dnoeth comment I can agree, probably we should use inner join when join table_c:
SELECT SUM(a.hours) AS total
FROM table_a a
LEFT JOIN table_b b
ON a.table_b_id = b.id
INNER JOIN table_c c
ON b.table_c_id = c.id
AND c.title IN ('Title D','Title E')
WHERE a.customer_id = 1
Use LEFT JOIN in both places and add this composite index:
INDEX(customer_id, title)

Get distinct value from join query (Join Table)

How get a distinct value form more than one table (inner join query).
Eg,
select a.id,b.name,c.address
from table1 a
inner join table2 b on (a.id = b.row_id)
inner join table3 c on (a.id = c.ticket_id)
where c.status = 'open';
Here the scenario is for example, two rows contain the same a.id value so how to get the distinct value from a.id.
Somebody help me that how to get?
just add Distinct ...
select DISTINCT a.id,b.name,c.address
from table1 a
inner join table2 b on (a.id = b.row_id)
inner join table3 c on (a.id = c.ticket_id)
where c.status = 'open';
i think this is works fine..
if you need only one record distinct then it should be like this...
SELECT DISTINCT(cat_id) FROM PRODUCTS WHERE brand_id = 'sony'

SQL LEFT JOIN only newest right column entry?

So I have two tables like this:
create table A
{
id int;
...
}
create table B
{
id int;
a_id int;
t timestamp;
...
}
A is one-to-many with B
I want to:
SELECT * FROM A LEFT JOIN B ON A.id = B.a_id ???
But I want to return exactly one row for each entry in A which has the B with the newest t field (or null for Bs fields if it has no B entry).
That is rather than returning all A-B pairs, I want to only select the newest one with respect to A (or A-null if no B entry).
Is there some way to express this in SQL? (I'm using MySQL 5.5)
LEFT JOIN is only concerned with ensuring every row in A is returned, even if there is no corresponding joined row in B.
The need for just one row needs another condition. MySQL is limitted in its options, but one could be:
SELECT
*
FROM
A
LEFT JOIN
B
ON B.id = A.id
AND B.t = (SELECT MAX(lookup.t) FROM B AS lookup WHERE lookup.id = A.id)
Another could be...
SELECT
*
FROM
A
LEFT JOIN
(
SELECT id, MAX(t) AS t FROM B GROUP BY id
)
AS lookup
ON lookup.id = A.id
LEFT JOIN
B
ON B.id = lookup.id
AND B.t = lookup.t
You could do the following:
SELECT A.*, B.*
FROM
A
LEFT JOIN
(SELECT B.a_id, MAX(t) as t FROM B GROUP BY B.a_id) BMax
ON A.id = BMax.a_id
JOIN B
ON B.a_id = BMax.a_id AND B.t = BMax.t
you first need to get the newest t from tableB in a subquery, then join it with tableA and tableB.
SELECT a.*, c.*
FROM tableA a
LEFT JOIN
(
SELECT a_ID, max(t) maxT
FROM tableB
GROUP BY a_ID
) b on a.a_id = b.a_ID
LEFT JOIN tableB c
ON b.a_ID = c.a_ID AND
b.maxT = c.t
try this:
SELECT *
FROM tableA A LEFT JOIN
(select a_id ,max(t) as max_t
from tableB
group by a_id )b
on A.id = b.a_id
and A.t=b.max_t

Help with JOINs in query

SELECT * FROM
Table_A
LEFT JOIN Table_B
ON (Table_A.A_ID = Table_B.A_ID)
INNER JOIN Table_C ON (Table_C.C_ID = Table_B.C_ID)
WHERE Table_A.ID = 3
This returns 0 rows, currently.
How can I set this up so I always get Table_A, even if there is no row for Table_B or Table_C. I still want to maintain the INNER JOIN between Table_B and Table_C, so that I will never get a B without a C.
Sub query the Table B and Table C. e.g.
SELECT *
FROM Table_A
LEFT JOIN
(SELECT *
FROM Table_B
INNER JOIN Table_C ON (Table_C.C_ID = Table_B.C_ID)
) B_AND_C ON (Table_A.A_ID = B_AND_C.A_ID)
WHERE Table_A.ID = 3
You may not have to use an inline view. I'm not in front of a machine with MySQL right now so I can't check but you can try
SELECT *
FROM table_A a
LEFT JOIN (table_B b
INNER JOIN table_C c
ON b.c_id = c.c_id)
ON a.b_id = b.b_id
WHERE
a.a_id =3