Mysql Puzzle : Conditions in ON vs. WHERE - mysql

The following two queries do not return the same result. Why ?
Note : I found this question as a Mysql puzzle, I don't have more data on this question?
SELECT table1.*
FROM table1 LEFT JOIN table2
ON table2.table1_id = table1.id
AND table2.val < 5
SELECT table1.*
FROM table1 LEFT JOIN table2
ON table2.table1_id = table1.id
WHERE table2.val < 5

The left outer join will return rows (with null columns from table2 if they were selected) when the condition isn't met, whereas the WHERE filters them out.

The first query will return all rows from table 1. A LEFT JOIN always returns all rows from the left table regardless of what you write in the join condition (it can however duplicate rows if there are multiple matches, but since you are joining on a field called id, it is most likely a unique key, so there will be no duplicates).
The second query will only return those rows from table 1 where the corresponding row in table2 has val < 5. You could in fact have written INNER JOIN here instead of LEFT JOIN because the rows where the join fails will not be in the result set anyway due to the WHERE clause.

First query only joins if table2.val < 5. Second filters even table1 rows. Identical result should be given if you use INNER JOIN instead.

Trying to think as a "compiler" look the parenthesis...
SELECT table1.*
FROM table1
LEFT JOIN table2 ON (
table2.table1_id = table1.id
AND table2.val < 5
)
This example does the LEFT JOIN of 2 tables when the condition table2.table1_id = table1.id AND table2.val < 5 is true.
SELECT table1.*
FROM table1
LEFT JOIN table2 ON ( table2.table1_id = table1.id )
WHERE (table2.val < 5)
This example do the LEFT JOIN when the condition table2.table1_id = table1.idapplies and then get the rows of the result of table1 LEFT JOIN table2 ON ( table2.table1_id = table1.id ) WHERE the condition table2.val < 5 is true

Related

Return multiple rows from subquery

Basically I have two tables. 1 and 2. I need the field2 column in the table2 table to return multiple rows. I tried the below join (simplified the columns) but unfortunately it returns me only one result.
SELECT table1.field1, table1.field2, table1.field3, sub_q.field4
FROM table1
JOIN (
SELECT t2.field4, t2.filter1, t2.filter2 FROM table2 t2
) sub_q ON (sub_q.filter1 = table1.id AND sub_q.filter2 = 1)
##Should return multiple rows
##but returns only one!
WHERE table1.id = ..;
Edit:
I created a schema here: http://sqlfiddle.com/#!9/1c5737 with the select query as
SELECT t1.field1, t1.field2, t1.field3, t2.field1
FROM table1 t1
JOIN table2 t2 ON t2.filter1 = t1.id AND t2.filter2 = 1
WHERE t1.id = 1;
Only to find out that it works there, so I come back in shame to accept the answer and check where I messed up in my query (probably one of the fields)
Why are you using a subquery in the join? This is how it should be written:
SELECT table1.field1, table1.field2, table1.field3, t2.field1
FROM table1 t1
JOIN table2 t2 ON t2.filter1 = table1.id AND t2.filter2 = 1
Also it is likely that you need LEFT JOIN (or INNER JOIN) instead of JOIN, but cannot be sure without more details on what you're trying to achieve.

How to combine 2 columns from 2 tables and subtract duplicates

I have 2 tables t1 and t2. Each have a customer ID column. What I am looking for is to join the 2 columns and SUBTRACT the duplicates.
My EG:
Table1 and Table2 with the IDs for each
I have tried a union query. The result I am left with is ID = 1,2,3,4,5,6,7,8,9,10. Where, what I'm after is subtracting 1-5 from Table2 and the result = 6,7,8,9,10.
I hope that makes sense and that someone is able to help. Sorry if this is a bit too simple compared to what you're all used to.
In SQL Server you can use the EXCEPT operator:
select ID
from Table2
except
select ID
from Table1
Mysql does not support it though. Using a an in clause or a left join would work in both servers:
--Using In clause
SELECT ID
FROM Table2
WHERE ID NOT IN
(
SELECT ID
FROM Table1
);
--Using join
SELECT Table2.ID
FROM Table2
left join Table1
on Table2.ID = Table1.ID
where Table1.ID is null
Use left outer join
select * from t1 left outer join t2 on t1.customerid = t2.customerid

MySQL conditional subquery

I am trying to run a subquery based on a condition:
SELECT `table1`.`id`, (
SELECT `table2`.`name`
FROM `table2`
WHERE `table2`.`id` = `table1`.`table2_id`
)
conditional on table2_id not being 0.
So if it's zero, only table1.id gets selected, else table1.id and table2.name gets selectectected. Assume I'll inner join the tables later.
I tried both CASE THEN and IF (), but I can't get the syntax to work.
I'm using MySQL 5.5
So it sounds like you simply want to left join to table 2 ? This means it will show all table1.id, and if table 2 matches it will show otherwise it will be null
SELECT table1.id, table2.name
From table1
Left join table2
on table1.table2_id = table2.id

3 tables and 2 left joins

Query 1:
SELECT sum(total_revenue_usd)
FROM table1 c
WHERE c.irt1_search_campaign_id IN (
SELECT assign_id
FROM table2 ga
LEFT JOIN table3 d
ON d.campaign_id = ga.assign_id
)
Query 2:
SELECT sum(total_revenue_usd)
FROM table1 c
LEFT JOIN table2 ga
ON c.irt1_search_campaign_id = ga.assign_id
LEFT JOIN table3 d
ON d.campaign_id = ga.assign_id
Query 1 gives me the correct result where as I need it in the second style without using 'in'. However Query 2 doesn't give the same result.
How can I change the first query without using 'in' ?
The reason being is that the small query is part of a much larger query, there are other conditions that won't work with 'in'
You could try something along the lines of
SELECT sum(total_revenue_usd)
FROM table1 c
JOIN
(
SELECT DISTINCT ga.assign_id
FROM table2 ga
JOIN table3 d
ON d.campaign_id = ga.assign_id
) x
ON c.irt1_search_campaign_id = x.assign_id
The queries do very different things:
The first query sums the total_revenue_usd from table1 where irt1_search_campaign_id exists in table2 as assign_id. (The outer join to table3 is absolutely unnecessary, by the way, because it doesn't change wether a table2.assign_id exists or not.) As you look for existence in table2, you can of course replace IN with EXISTS.
The second query gets you combinations of table1, table2 and table3. So, in case there are two records in table2 for an entry in table1 and three records in table3 for each of the two table2 records, you will get six records for the one table1 record. Thus you sum its total_revenue_usd sixfold. This is not what you want. Don't join table1 with the other tables.
EDIT: Here is the query using an exists clause. As mentioned, outer joining table3 doesn't alter the results.
Select sum(total_revenue_usd)
from table1 c
where exists
(
select *
from table2 ga
-- left join table3 d on d.campaign_id = ga.assign_id
where ga.assign_id = c.irt1_search_campaign_id
);

Linking 3 tables together in MySQL

I'm trying to link 3 database table together through one MySQL request.
Database structure :
Table1 :
table1_id (exemple: 1)
table1_name (exemple: hello world)
Table2 :
table2_id (exemple: empty)
table2_name (exemple: empty)
Table3 :
table3_id (exemple: 1)
table3_name (exemple: random_name
MySQL Request
SELECT * FROM table1 AS a, table2 AS b, table3 AS c
WHERE a.table1_id = b.table2_id
AND a.table1_id = c.table3_id AND table3_name = "random-name"
Problem
The previous request won't display any result because table2 is empty. Do you have an idea how I could get the data coming from table 1 & 2, letting table3's fields empty without using two requests ?
You should change your request to use a LEFT JOIN instead of an INNER JOIN:
select *
from table1 t1
left join table2 t2
on t1.table1_id = t2.table2_id
left join table3 t3
on t1.table1_id = t3.table2_id
and t3.table3_name = 'random-name'
The INNER JOIN produces a set of data if the id exists in all tables. The LEFT JOIN will return records from table1 even if there are no records in table2 or table3.
If you need help learning about join syntax, here is a great visual explanation of joins
Couple thoughts:
Don't use SELECT *, name the columns explicitly
Don't use implicit join syntax; use ON clauses
To preserve rows that do not "match" on a join condition, use a LEFT OUTER JOIN
Therefore, try this:
SELECT a.table1_id, a.table1_name
, b.table2_id, b.table2_name
, c.table3_id, c.table3_name
FROM table1 AS a
LEFT OUTER JOIN table2 AS b
ON b.table2_id = a.table1_id
JOIN table3 AS c
ON c.table3_id = a.table1_id
WHERE c.table3_name = "random-name"