Firebird 到 MySQL 查询迁移 - Select 内连接子查询
Firebird to MySQL query migration - Select Inner Join Subquery
我有一个在我们的 Firebird SQL 数据模块中有效的查询。
我们迁移到 MySQL,我的所有查询都没有问题,除了这个。
请帮我解决这个问题。我得到一个错误:
Failed to Execute. Unknown column 'part.id' in 'on clause'
我的 Firebird 查询:
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
除了在子查询中创建的 lowestcost
和 highestcost
外,所有表都在数据库中。
希望我的要求写清楚了。但总而言之——我需要迁移这个有效的 Firebird 查询以在 MySQL.
中工作
为什么这在 Firebird 中有效,但在 MySQL 中无效?
问题是 mySQL 中的 comma operator has lower precedence 比 join
运算符要大,因此 product inner join (subquery) on part.id = highestcost.partid inner join (subquery) on part.id = lowestcost.partid
联接在 之前 part
table 加入了表达式,因此出现错误消息。
用简单的 join
运算符替换逗号运算符并将连接条件从 where
子句移动到 on
子句,一切都会好起来的:
...
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
如果您有更多混合逗号运算符和显式连接的此类查询,那么您应该检查它们,因为即使 MySQL.[=18= 中没有语法错误,它们也可能会产生不同的结果]
此查询在 Firebird 3.0 及更高版本中也不起作用(请参阅 Support for Mixed-Syntax Joins is Gone)。原因是您将 SQL-89 样式连接与 SQL-92 样式连接组合在一起。
您需要重写查询以在所有地方使用显式连接,因此:
...
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
不要混用显式和隐式联接
避免在列和 table 名称中使用相同的别名(在此示例中 ai 指的是 t1 和 t2 )
并避免 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
我有一个在我们的 Firebird SQL 数据模块中有效的查询。
我们迁移到 MySQL,我的所有查询都没有问题,除了这个。
请帮我解决这个问题。我得到一个错误:
Failed to Execute. Unknown column 'part.id' in 'on clause'
我的 Firebird 查询:
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
除了在子查询中创建的 lowestcost
和 highestcost
外,所有表都在数据库中。
希望我的要求写清楚了。但总而言之——我需要迁移这个有效的 Firebird 查询以在 MySQL.
中工作为什么这在 Firebird 中有效,但在 MySQL 中无效?
问题是 mySQL 中的 comma operator has lower precedence 比 join
运算符要大,因此 product inner join (subquery) on part.id = highestcost.partid inner join (subquery) on part.id = lowestcost.partid
联接在 之前 part
table 加入了表达式,因此出现错误消息。
用简单的 join
运算符替换逗号运算符并将连接条件从 where
子句移动到 on
子句,一切都会好起来的:
...
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
如果您有更多混合逗号运算符和显式连接的此类查询,那么您应该检查它们,因为即使 MySQL.[=18= 中没有语法错误,它们也可能会产生不同的结果]
此查询在 Firebird 3.0 及更高版本中也不起作用(请参阅 Support for Mixed-Syntax Joins is Gone)。原因是您将 SQL-89 样式连接与 SQL-92 样式连接组合在一起。
您需要重写查询以在所有地方使用显式连接,因此:
...
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
不要混用显式和隐式联接
避免在列和 table 名称中使用相同的别名(在此示例中 ai 指的是 t1 和 t2 )
并避免 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