MySQL LEFT JOIN after 5.0.12 changes - How to rewrite query - mysql

After 5.0.12 MySQL changed the syntax for left joins to match SQL2003 standard. So
... FROM t1 , t2 LEFT JOIN t3 ON (expr)
needs to be rewritten as
... FROM (t1 , t2) LEFT JOIN t3 ON (expr
or else it will be parsed as ... FROM t1 , (t2 LEFT JOIN t3 ON (expr))
Now, I have an ancient app I'm porting from MySQL 3.23 (eek!) to 5.1, and the old code has this query:
select b.*, c.*, g.*, p.perfname, p.persname
from bookings b, customer c
left join grade g on b.chrggrade=g.grcode
left join person p on b.person=p.percode
where complete='Y' and invoiced='N'
and datemade between '2009-03-25' and '2009-03-31'
and c.custcode=b.cust
order by cust, person, tsref, stdt
This fails with SQL error 1054, unknown column in b.chrggrade. This is because it's parsing as
select b., c., g.*, p.perfname, p.persname
from bookings b, (customer c
left join grade g on b.chrggrade=g.grcode )
left join person p on b.person=p.percode
where complete='Y' and invoiced='N'
and datemade between '2009-03-25' and '2009-03-31'
and c.custcode=b.cust
order by cust, person, tsref, stdt
I think.
I'm sure correctly placed brackets can fix this but I'm stumped.
I found reference to this change at http://bugs.mysql.com/bug.php?id=13551, which shows how to fix a simple left join, but I still can't work it out for this query.
David

Stop using the comma syntax altogether and be explicit in your JOIN statements. The comma syntax forces you to put the JOIN condition in the WHERE clause, which may not get executed until after LEFT/RIGHT joins, depending on how it's parsed. Using explicit JOINS makes the query more readable anyway.
...FROM t1, t2 LEFT JOIN t3 ON (expr)
becomes
...FROM t1 INNER JOIN t2 ON (expr) LEFT JOIN t3 ON (expr)
That will also fix the error you are seeing. Unless there is no chrggrade in the bookings table, then nothing will fix the error.

Related

Get results from second table joined even if the initial select fails and vice versa

I am using the SELECT statement below to join the property table with the epc table. Not always is the EPC available for a property. I also want the epc table if the property does not exist.
SELECT p.dateAdded, p.paon, p.saon, p.street, p.locality, p.townCity, p.district, p.county, p.propertyType,
p.propertyType, p.oldNew, p.postcode, p.tenure, p.ppd, p.bedrooms, p.bathrooms, p.receptions, p.lastSalePrice, p.lastTransferDate,
e.INSPECTION_DATE, e.TOTAL_FLOOR_AREA, e.CURRENT_ENERGY_RATING, e.POTENTIAL_ENERGY_RATING, e.CURRENT_ENERGY_EFFICIENCY, e.POTENTIAL_ENERGY_EFFICIENCY,
e.PROPERTY_TYPE
FROM property p
LEFT JOIN epc e ON p.postcode = e.POSTCODE AND CONCAT(p.paon, ', ', p.street) = e.ADDRESS1
WHERE p.paon = 8 AND p.postcode = "TS6 9LN"
ORDER BY e.INSPECTION_DATE, p.lastTransferDate DESC
LIMIT 1
Is it possible to select both tables but if 1 doesn't exist, select the 1 that does?
You need a FULL OUTER JOIN. Unfortunately MySQL does not implement this part of the SQL standard. You can simulate a full outer join with two outer joins, though, but it becomes long, and possibly quite cumbersome and error prone.
For example:
select a.col1, b.col2
from table_a a
LEFT join table_b b on ...
union -- here we union both outer joins
select a.col1, b.col2
from table_a a
RIGHT join table_b b on ...
In the second SELECT the table roles are inverted, since it uses a RIGHT JOIN instead of a LEFT JOIN.

Syntax error in full outer join?

I have a query where I am using a full outer join. But in some instance,
it gives me a syntax error.
What could be the reason for this? I don't see any miscode in my query.
MySQL does not support full outer join, but you can simulate it as a union between a left and right join query:
SELECT * FROM pbsdev3.item t1
LEFT JOIN pbsdev3.item_ledger_entry t2 ON t1.No_ = t2.Item_No_
UNION ALL
SELECT * FROM pbsdev3.item t1
RIGHT JOIN pbsdev3.item_ledger_entry t2 ON t1.No_ = t2.Item_No_
WHERE t1.No_ IS NULL
Note that in general if you find yourself doing full outer joins often, it could imply that your keys and data model are not well defined. One reason why MySQL does not support full joins could be that you should not have to use it.
Full outer join is quite a pain in MySQL. The first thing I would note is that it should not be needed. The items should match in the two tables, so an inner join or left join should be sufficient:
SELECT i.*, ile.*
FROM pbsdev3.item i LEFT JOIN
pbsdev3.item_ledger_entry ile
ON i.No_ = ile.Item_No_;
If you really need full outer join, then gather together all the items and use left join:
select it.*, ile.*
from (select i.No_ from item i union
select ile.Item_No_ from item_ledger_entry ile
) i left join
item it
on it.No_ = i.No_ left join
item_ledger_entry ile
on ile.No = i.No;

Can't do 2 joins on an MS Access query?

So I have checked all the names etc are correct, the query works with only one of the joins not both with a syntax error:
SELECT *, Invoice_Accounts.Title AS t1, Invoice_Accounts.Forename AS f1, Invoice_Accounts.Surname AS s1
FROM Invoice_Accounts
RIGHT JOIN Delivery_Points ON Invoice_Accounts.Account_No = Delivery_Points.Account_No
RIGHT JOIN Companies ON Invoice_Accounts.account_id = Companies.Company_No
This is the query I want to run but it comes up with the error:
syntax error (missing operator)
UPDATE:
using:
SELECT *,
Invoice_Accounts.Title AS t1,
Invoice_Accounts.Forename AS f1,
Invoice_Accounts.Surname AS s1
FROM (Invoice_Accounts
RIGHT JOIN Delivery_Points
ON Invoice_Accounts.Account_No = Delivery_Points.Account_No)
RIGHT JOIN Companies
ON Invoice_Accounts.account_id = Companies.Company_No
Gets me the error "JOIN expression not supported"
In Access you need to use parenthesis around joins if you have more than one:
SELECT *,
Invoice_Accounts.Title AS t1,
Invoice_Accounts.Forename AS f1,
Invoice_Accounts.Surname AS s1
FROM (Invoice_Accounts
RIGHT JOIN Delivery_Points
ON Invoice_Accounts.Account_No = Delivery_Points.Account_No)
RIGHT JOIN Companies
ON Invoice_Accounts.account_id = Companies.Company_No
Two extend this, if you had three joins, you would need another set of parentheses:
SELECT *
FROM (( A
INNER JOIN B
ON B.AID = A.AID)
INNER JOIN C
ON C.BID = B.BID)
INNER JOIN D
ON D.CID = C.CID;
EDIT
I did not know that you could not RIGHT JOIN to the same table twice, so the above is an error, having said that I have never used a RIGHT JOIN in production code in my life, I would be inclined to switch to the more widely used LEFT JOIN and change the order of the tables:
SELECT *,
ia.Title AS t1,
ia.Forename AS f1,
ia.Surname AS s1
FROM (Companies AS c
LEFT JOIN Invoice_Accounts AS ia
ON ia.account_id = c.Company_No)
LEFT JOIN Delivery_Points AS dp
ON ia.Account_No = dp.Account_No;
N.B. I have used aliases to reduce the amount of text in the query, this (in my opinion) makes them easier to read
Figured out the answer eventually:
SELECT Invoice_Accounts.Title AS t1, Invoice_Accounts.Forename AS f1, Invoice_Accounts.Surname AS s1, *
FROM (Companies
RIGHT JOIN Invoice_Accounts ON Companies.Company_No = Invoice_Accounts.Company_Name
)
RIGHT JOIN Delivery_Points ON Invoice_Accounts.Account_No = Delivery_Points.Account_No;
The issue arises from ancient ms-access technologies where you can't right join to the same table more than once!

MS Access Multi-Join Query

Can anyone find what is wrong with this MS Access Query? When I try to execute it i receive an error about a missing Operator before the 2nd Left Join
SELECT * FROM (
SELECT GetitUsageTemp.MemberID,
GetitUsageTemp.IDNumber,
GetitUsageTemp.Title,
GetitUsageTemp.Initials,
GetitUsageTemp.Forenames,
GetitUsageTemp.Surnames,
GetitUsageTemp.CellNumber,
GetitUsageTemp.EmailAddress,
Nz(August.[AugustUsage],0) AS AugustUsage
FROM GetitUsageTemp
LEFT JOIN
(SELECT dbo_Requests.fk_Members_ID, Count(dbo_Requests.Log_date) AS JulyUsage
FROM dbo_Requests
WHERE dbo_Requests.Log_date Between #07/01/2013# And #08/01/2013#
GROUP BY dbo_Requests.fk_Members_ID
) Requests
ON GetitUsageTemp.MemberID = Requests.fk_Members_ID
LEFT JOIN
(SELECT dbo_Requests.fk_Members_ID, Count(dbo_Requests.Log_date) AS AugustUsage
FROM dbo_Requests
WHERE dbo_Requests.Log_date Between #08/01/2013# And #09/01/2013#
GROUP BY dbo_Requests.fk_Members_ID
) August
ON GetitUsageTemp.MemberID = August.fk_Members_ID
)GETIT
In Access you can only join two tables. If you need to join more tables, you need to group the first join together using parentheses, as if it was a new derived table. Then you can join another table to that group:
select
*
from
( ( Table1
LEFT JOIN Table2 ...
)
LEFT JOIN Table3 ...
)
LEFT JOIN Table4 ...
(I'm using awkward indentation to try to make the groups more clear)

MySQL JOIN query worked in version 4, broken in 5

I've inherited a website someone else built using MySQL 4 as the database and am trying to switch to a new server, running MySQL 5. I copied all files across and dumped the database from MySQL version 4 and then imported back into version 5.
Now, half of the website is working while the other half is not. I keep getting the following:
Unknown column 'a.id_art' in 'on clause'
Here's my query:
SELECT *, aks.nazwa as sekcja, ak.nazwa kategoria
FROM
artykuly a,
artykuly_kategorie ak,
artykuly_sekcje aks
LEFT JOIN artykuly_addons aad ON aad.id_art=a.id_art
WHERE a.id_art = '20' AND ak.id_sek = aks.id_sek AND a.id_kat = ak.id_kat
Why does the above work fine in MySQL version 4 but is a broken man in version 5?
Probably the combination of LEFT JOIN and joining with commas and filtering in the WHERE clause causes the problem. Try this:
SELECT *, aks.nazwa as sekcja, ak.nazwa kategoria
FROM
artykuly a INNER JOIN artykuly_kategorie ak ON a.id_kat = ak.id_kat
INNER JOIN artykuly_sekcje aks ON ak.id_sek = aks.id_sek
LEFT JOIN artykuly_addons aad ON aad.id_art=a.id_art
WHERE a.id_art = '20'
The precedence of the comma is now lower than explicit JOIN statements. Quoting the MySQL 5.0 JOIN Syntax page:
Previously, the comma operator (,) and JOIN both had the same
precedence, so the join expression t1, t2 JOIN t3 was interpreted as
((t1, t2) JOIN t3). Now JOIN has higher precedence, so the expression
is interpreted as (t1, (t2 JOIN t3))
So previously this was treated as
SELECT *,
aks.nazwa as sekcja,
ak.nazwa kategoria
FROM
(
(
artykuly a,
artykuly_kategorie ak0
),
artykuly_sekcje aks
)
LEFT JOIN artykuly_addons aad ON aad.id_art=a.id_art
WHERE a.id_art = '20'
AND ak.id_sek = aks.id_sek
AND a.id_kat = ak.id_kat
Now it is interpreted as:
SELECT *,
aks.nazwa as sekcja,
ak.nazwa kategoria
FROM
(
(
artykuly a,
artykuly_kategorie ak0
),
(artykuly_sekcje aks LEFT JOIN artykuly_addons aad ON aad.id_art=a.id_art)
)
WHERE a.id_art = '20'
AND ak.id_sek = aks.id_sek
AND a.id_kat = ak.id_kat