Firebird to MySQL query migration - Select Inner Join Subquery

≯℡__Kan透↙ 提交于 2019-12-23 20:34:31

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!