【问题标题】:Firebird to MySQL query migration - Select Inner Join SubqueryFirebird 到 MySQL 查询迁移 - 选择内部连接子查询
【发布时间】:2023-03-24 02:37:01
【问题描述】:

我有一个在 Firebird SQL 数据模块中有效的查询。

我们迁移到 MySQL,我的所有查询都没有问题,除了这个。

请帮我解决这个问题。我收到一个错误:

执行失败。 “on 子句”中的未知列“part.id”

我的 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 

除了在子查询中创建的lowestcosthighestcost 之外,所有表都在数据库中。

希望我的要求写得很清楚。但总而言之 - 我需要将这个有效的 Firebird 查询迁移到 MySQL 中。

为什么这在 Firebird 中有效,但在 MySQL 中无效?

【问题讨论】:

  • 不要混合逗号连接语法和内连接语法..
  • 请问您为什么要迁移到 MySQL?
  • @skafinski 我们的库存管理系统昨天刚刚更新到新版本。整个系统从 Firebird SQL 迁移到 MySQL。到目前为止,性能有了更好的提升,查询的编译速度也更快。

标签: mysql select join nested firebird


【解决方案1】:

问题是在 mySQL 中 comma operator has lower precedencejoin 运算符,因此 product inner join (subquery) on part.id = highestcost.partid inner join (subquery) on part.id = lowestcost.partid 连接被评估之前 part 表被连接到表达式中,因此错误消息。

用简单的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 中没有语法错误,它们也可能产生不同的结果。

【讨论】:

  • 谢谢影子。这是第一个答案,并且立即起作用。简单的解释。
  • 在 Firebird 中混合显式 (SQL-92) 和隐式 (SQL-89) 连接也被认为是不好的风格,已知这会导致意想不到的效果甚至错误。即使对于最初的 Firebird 数据库,这些查询也最好重新处理
【解决方案2】:

此查询在 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 

【讨论】:

    【解决方案3】:

    不要混合显式和隐式连接
    避免在列名和表名中使用相同的别名(在此示例中 ai 指的是 t1 和 t2 ) 并避免子选择表名的 AS

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-20
      • 2016-01-04
      • 1970-01-01
      • 2013-12-16
      • 2021-11-09
      • 1970-01-01
      相关资源
      最近更新 更多