Multiple JOINS do not work in a nested JOIN - mysql

Why am I unable to join multiple tables?
If I were to run this SQL code without the second INNER JOIN, it works just fine.
SELECT a.name, c1.text, c2.text
FROM `table_a` a
INNER JOIN (
`table_b` b
INNER JOIN `table_c1` c1 ON b.info_id = c1.id
INNER JOIN `table_c2` c2 ON b.info_id = c2.id
) ON a.id = b.person_id;
However, if I add a second JOIN -> INNER JOIN table_c2 c2 ON b.info = c2.id, it ceases to work properly, and won't select anything.
Here is a sqlfiddle for the following problem.
My desired result is that I want it to select from both tables
table_c1 and table_c2.
Here it selects only with table_c1.
SELECT a.name, c1.text
FROM `table_a` a
INNER JOIN (
`table_b` b
INNER JOIN `table_c1` c1 ON b.info_id = c1.id
) ON a.id = b.person_id;
I would want there to be a third row with name "Bob", and text "more_other_table_text"

There are a few things you can do to achieve this:
LEFT JOIN between table_b and c1 & c2.
IFNULL to check for text in c1, otherwise return text from c2.
GROUP BY without an aggregate function to remove the duplicate Sam values from the result set based on the order they were entered into table_2 (you did not specify what value you want when the same person_id is entered multiple times in table_2, if you would like to see both c1 and c2 texts with duplicate names, remove the GROUP BY).
See Fiddle
SELECT a.name, IFNULL(c1.text, c2.text) as `text`
FROM `table_a` a
INNER JOIN (
`table_b` b
LEFT JOIN `table_c1` c1 ON b.info_id = c1.id
LEFT JOIN `table_c2` c2 ON b.info_id = c2.id
) ON a.id = b.person_id
GROUP BY a.name
ORDER BY a.id ASC

The simplest solution is to put your join condition next to the join:
SELECT a.name, b.age, c1.text, c2.text
FROM table_a a
INNER JOIN table_b b ON a.id = b.person_id
INNER JOIN table_c1 c1 ON b.info = c1.id
INNER JOIN table_c2 c2 ON b.info = c2.id
You may also use parentheses, but there is no advantage to doing so:
SELECT a.name, b.age, c1.text, c2.text
FROM table_a a
INNER JOIN (
table_b b
INNER JOIN table_c1 c1 ON b.info = c1.id
INNER JOIN table_c2 c2 ON b.info = c2.id
)
ON a.id = b.person_id

Related

Join Three Tables On Two Columns

I'm using this to join 3 tables
FROM TABLE_A LEFT JOIN TABLE_B ON A.Name = B.Name
LEFT JOIN TABLE_C ON A.Name = C.Name
Whenever I try something like
FROM TABLE_A LEFT JOIN TABLE_B ON A.Name = B.Name, A.Number = B.Number
LEFT JOIN TABLE_C ON A.Name = C.Name, A.Number = C.Number
It tells me I can only use one column for this operation. I need to join on two different columns though so I can't leave it at the first example. Using AND didn't help me either.
Try to replace the comma between the dual tests with an operator.
such as:
FROM TABLE_A LEFT JOIN TABLE_B ON A.Name = B.Name AND A.Number = B.Number
LEFT JOIN TABLE_C ON A.Name = C.Name AND A.Number = C.Number

join 3 tables if 3rd table does not have that value

Table 1
id , userid, eventid , name
table 2
eventid , zoneid , userid
table 3
eventid , userid, status
if all three table having the eventid means i dont want to select that record (i mean if table 3 have the eventid), else i need to select records
i tried my query
SELECT
*
FROM
`table1` c1
INNER JOIN `table2` c2 ON c2.eventid = c1.eventid
LEFT JOIN table3 c3 ON c3.eventid = c1.eventid
WHERE
c2.zoneid=2
AND c1.active='1'
GROUP BY
c1.eventid
Add a where clause where there is no c3:
SELECT *
FROM `table1` c1
INNER JOIN `table2` c2 ON c2.eventid = c1.eventid
LEFT JOIN table3 c3 ON c3.eventid = c1.eventid
WHERE c2.zoneid=2 AND c1.active='1'
AND c3.id IS NULL
group by c1.eventid
SELECT
*
FROM
`table1` c1
INNER JOIN `table2` c2 ON c2.eventid = c1.eventid
WHERE
c2.zoneid=2
AND c1.active='1'
AND NOT EXISTS (SELECT * FROM table3 c3 WHERE c3.eventid = c1.eventid)
GROUP BY
c1.eventid
Applying a WHERE-condition (like some of the other answers suggest) on a table that has been joined through a LEFT/RIGHT OUTER JOIN will actually make it a regular join.
The other examples that have been posted ask c1.eventid to equal c3.eventid, and c3.eventid to be NULL - good chance that the result will be not what you expect, depending on how the database treats c1.eventid = c3.eventid if both are NULL (I'd have to read up on that).
A Left join on the 3rd table and the condition WHERE C.eventid IS NULL should do the work.
SELECT *
FROM table1 A
INNER JOIN table2 B
ON A.eventid = B.eventid
LEFT OUTER JOIN table3 C
ON A.eventid = C.eventid
WHERE C.eventid IS NULL

Is left join commutative? What are its properties?

Assume tables TableA TableB TableC and TableD:
Is the following query:
TableA INNER JOIN TableB LEFT JOIN TableC LEFT JOIN TableD
(all joined to an id column) equivalent to:
TableA INNER JOIN TableB
INNER JOIN TableC
LEFT JOIN TableD
UNION
TableA INNER JOIN TableB
LEFT JOIN TableC ON TableB.c_id IS NULL
LEFT JOIN TableD
?
Note:
Or instead of union just do
TableA INNER JOIN TableB
INNER JOIN TableC
LEFT JOIN TableD
And then
TableA INNER JOIN TableB
LEFT JOIN TableC ON TableB.c_id IS NULL
LEFT JOIN TableD
and then combine the results
Update
Is
(A INNER JOIN B) LEFT JOIN C LEFT JOIN D
the same as:
A INNER JOIN (B LEFT JOIN C) LEFT JOIN D
?
Wikipedia:
"In mathematics, a binary operation is commutative if changing the order of the operands does not change the result. It is a fundamental property of many binary operations, and many mathematical proofs depend on it."
Answer:
no, a left join is not commutative. And inner join is.
But that's not really what you are asking.
Is the following query:
TableA INNER JOIN TableB LEFT JOIN TableC LEFT JOIN TableD
(all joined to an id column) equivalent to:
TableA INNER JOIN TableB
INNER JOIN TableC
LEFT JOIN TableD
UNION
TableA INNER JOIN TableB
LEFT JOIN TableC ON TableB.c_id IS NULL
LEFT JOIN TableD
Answer:
Also no. Unions and joins don't really accomplish the same thing, generally speaking. In some case you may be able to write them equivalently, but I don't think so general pseudo sql you are showing. The ON constitution seemslike it should not work (maybe something about which I do not know in MySQL?)
Here is a simplified set of queries that I do think would be equivalent.
SELECT *
FROM TableA a
LEFT JOIN
TableB b ON a.id = b.id_a
SELECT *
FROM TableA a
INNER JOIN
TableB b ON a.id = b.id_a
UNION
SELECT *
FROM TableA a
LEFT JOIN
TableB b ON a.id = b.id_a
WHERE TableB.id IS NULL
Edit 2:
Here's another example that is closer to your but in essence the same.
SELECT *
FROM TableA a
INNER JOIN TableB b ON a.id = b.id_a
LEFT JOIN TableC c ON b.id = c.id_b
is the same as
SELECT *
FROM TableA a
INNER JOIN TableB b ON a.id = b.id_a
INNER JOIN TableC c ON b.id = c.id_b
UNION
SELECT *
FROM TableA a
INNER JOIN TableB b ON a.id = b.id_a
LEFT JOIN TableC c ON b.id = c.id_b
WHERE TableC.id IS NULL
But I still don't think I'm answering your real question.

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'

MySQL Multiple Aggregates

Without the third join D.cid = C.id, this query gives me the count of C. With the third join it corrupts the count and gets unwanted tuples into the count of C's join. So how can I get the count of C and D without having the C count effected? Is there a form of parenthesis I can use to make sure I get the correct count?
SELECT A.*, B.*, COUNT(C.aid) AS cCount
FROM tableA A
LEFT JOIN tableC AS C ON A.id = C.aid
INNER JOIN tableB AS B ON A.id = B.aid
LEFT JOIN tableD AS D ON D.cid = C.id
GROUP BY A.id
I would have the counts from the other tables pre-aggregated unto themselves and joined... something like...
SELECT
A.*,
B.*,
COALESCE( PreAggC.CCount, 0 ) as CCount,
COALESCE( PreAggC.WithDCount, 0 ) as WithDCount
FROM
tableA A
JOIN tableB B
on A.ID = B.aID
LEFT JOIN ( select aID,
count( distinct id ) CCount,
count(*) as WithDCount
from tableC
left join tableD D
on c.ID = D.cID
group by aID ) PreAggC
on A.id = PreAggC.aID
Now, do you really want how many entries actually have "D" records? so I included both counts... distinct "C" entries, and the overall count with correlation with "D"