问题
I have a query that worked in our Firebird SQL data module.
We migrated to MySQL and all my queries work no problem except for this one.
Please help me fix this. I get an error:
Failed to Execute. Unknown column 'part.id' in 'on clause'
My Firebird query:
SELECT vendor.name AS "Vendor Name",
Cast(Cast(vendorparts.lastdate AS date) AS CHAR(10)) AS "Last Date",
CASE product.price
WHEN '0' THEN 'CONFIRM'
WHEN NULL THEN 'CONFIRM'
ELSE Round(product.price, 2)
end AS "D-Price",
Cast(vendorparts.lastcost AS DECIMAL(18, 2)) AS "Last Cost",
Cast(lowestcost.lowestcost AS DECIMAL(18, 2)) AS "Lowest Cost",
Cast(highestcost.highestcost AS DECIMAL(18, 2)) AS "Highest Cost",
part.num AS "Part Number",
part.description AS "Part Description"
FROM vendor,
vendorparts,
part,
product
INNER JOIN (SELECT vendorparts.partid,
Max(vendorparts.lastcost) AS Highestcost
FROM vendorparts
GROUP BY vendorparts.partid) AS highestcost
ON part.id = highestcost.partid
INNER JOIN (SELECT vendorparts.partid,
Min(vendorparts.lastcost) AS Lowestcost
FROM vendorparts
GROUP BY vendorparts.partid) AS lowestcost
ON part.id = lowestcost.partid
WHERE vendor.id = vendorparts.vendorid
AND product.partid = part.id
AND vendorparts.partid = part.id
AND vendorparts.lastcost <> 0
All tables are in the database except for lowestcost
and highestcost
which were created in the sub-queries.
Hopefully my request is clearly written. But to summarize - I need this working Firebird query to be migrated to work in MySQL.
Why would this work in Firebird but not MySQL?
回答1:
The problem is that in mySQL the comma operator has lower precedence than the join
operator, therefore the product inner join (subquery) on part.id = highestcost.partid inner join (subquery) on part.id = lowestcost.partid
joins are evaluated before the part
table is joined in the expression, hence the error message.
Replace the comma operators with simple join
operators and move the join conditions from the where
clause to on
clauses and all will be fine:
...
FROM vendor
inner join vendorparts on vendor.id = vendorparts.vendorid
inner join part on vendorparts.partid = part.id
inner join product on product.partid = part.id
INNER JOIN (SELECT vendorparts.partid,
Max(vendorparts.lastcost) AS Highestcost
FROM vendorparts
GROUP BY vendorparts.partid) AS highestcost
ON part.id = highestcost.partid
INNER JOIN (SELECT vendorparts.partid,
Min(vendorparts.lastcost) AS Lowestcost
FROM vendorparts
GROUP BY vendorparts.partid) AS lowestcost
ON part.id = lowestcost.partid
WHERE vendorparts.lastcost <> 0
If you have more such queries where you mix comma operator and explicit joins, then you should check them out because they may produce different results even if there was not syntax error in MySQL.
回答2:
This query would also not work in Firebird 3.0 and higher (see Support for Mixed-Syntax Joins is Gone). The reason is that you are combining SQL-89 style joins with SQL-92 style joins.
You need to rewrite the query to use explicit joins everywhere, so:
...
FROM vendor
inner join vendorparts on vendor.id = vendorparts.vendorid
inner join part on vendorparts.partid = part.id
inner join product on product.partid = part.id
INNER JOIN (SELECT vendorparts.partid,
Max(vendorparts.lastcost) AS Highestcost
FROM vendorparts
GROUP BY vendorparts.partid) AS highestcost
ON part.id = highestcost.partid
INNER JOIN (SELECT vendorparts.partid,
Min(vendorparts.lastcost) AS Lowestcost
FROM vendorparts
GROUP BY vendorparts.partid) AS lowestcost
ON part.id = lowestcost.partid
WHERE vendorparts.lastcost <> 0
回答3:
Don't mix explicit and implicit join
Avoid the use of same alias in column and table names (in this sample ai refer to t1 and t2 )
and avoid the AS for subselect table name
SELECT
vendor.name AS "Vendor Name",
Cast(Cast(vendorparts.lastdate AS date) AS CHAR(10)) AS "Last Date",
CASE product.price
WHEN '0' THEN 'CONFIRM'
WHEN NULL THEN 'CONFIRM'
ELSE Round(product.price, 2)
end AS "D-Price",
Cast(vendorparts.lastcost AS DECIMAL(18, 2)) AS "Last Cost",
Cast(lowestcost.lowestcost AS DECIMAL(18, 2)) AS "Lowest Cost",
Cast(highestcost.highestcost AS DECIMAL(18, 2)) AS "Highest Cost",
part.num AS "Part Number",
part.description AS "Part Description"
FROM vendor
INNER JOIN vendorparts on vendor.id = vendorparts.vendorid AND vendorparts.lastcost <> 0
INNER JOIN part on vendorparts.partid = part.id and
INNER JOIN product on product.partid = part.id
INNER JOIN (SELECT vendorparts.partid,
Max(vendorparts.lastcost) AS Highestcost
FROM vendorparts
GROUP BY vendorparts.partid) t1
ON part.id = t1.partid
INNER JOIN (SELECT vendorparts.partid,
Min(vendorparts.lastcost) AS Lowestcost
FROM vendorparts
GROUP BY vendorparts.partid) t2
ON part.id = t2.partid
来源:https://stackoverflow.com/questions/44702597/firebird-to-mysql-query-migration-select-inner-join-subquery