将这些 DB2 SUBQUERY 重写为 Join

Posted

技术标签:

【中文标题】将这些 DB2 SUBQUERY 重写为 Join【英文标题】:Rewrite these DB2 SUBQUERY into a Join 【发布时间】:2016-01-28 18:40:59 【问题描述】:

我有一些需要查询数据库的业务规则。现在下面的 sql 正在使用子查询,但我想将每个查询更改为一个 join 语句。

column oditnr:项目编号 column odredt:下单后的天数 列 odbcsn:客户#

我的数据库是 DB2,但我使用 mysql 创建了一个 sql fiddle http://www.sqlfiddle.com/#!9/3d10ae/3

我需要检查客户是否在过去 60 天内购买了编号为 1025926 的商品 如果查询返回结果,则客户购买了该商品。

SELECT ord1.oditnr, ord1.odredt, itm.imdesc  
FROM orderdetails ord1
  LEFT JOIN items itm ON ord1.oditnr = itm.imitnr
WHERE EXISTS (SELECT * 
              FROM orderdetails ord2 
              WHERE ord1.odbcsn = ord2.odbcsn 
                AND ord2.oditnr = '1022925'  
                AND odredt >= VARCHAR_FORMAT(CURRENT TIMESTAMP - 60 DAYS, 'YYYYMMDD') ) 
AND ord1.odbcsn = '11677'  
ORDER BY odredt desc ;

我需要检查客户在过去 60 天内是否没有购买过编号为 2521809 的商品 如果查询返回结果,则客户尚未购买该商品。

SELECT ord1.oditnr, ord1.odredt, itm.imdesc  
FROM orderdetails ord1
   LEFT JOIN items itm ON ord1.oditnr = itm.imitnr
WHERE NOT  EXISTS (SELECT * 
                   FROM orderdetails ord2 
                   WHERE ord1.odbcsn = ord2.odbcsn 
                     AND ord2.oditnr = '2521809'  
                     AND odredt >= VARCHAR_FORMAT(CURRENT TIMESTAMP - 60 DAYS, 'YYYYMMDD') ) 
AND ord1.odbcsn = '11677'  
ORDER BY odredt desc ;

【问题讨论】:

想评论为什么你需要加入? 我正在使用mistic100.github.io/jQuery-QueryBuilder 创建一个接口来构建查询。子查询对于插件来说太复杂了 你有什么问题? 我需要一些帮助,将上面的 2 个查询转换为不使用子查询的连接 请记住,联接的性能可能会更差,尤其是与 not exists 相比。为工作选择更好的工具(查询生成器)可能是更好的选择。 【参考方案1】:

如果您找不到其他支持子查询的工具,您可以尝试以下方法:

SELECT ord1.oditnr, ord1.odredt, itm.imdesc  
FROM orderdetails ord1
INNER JOIN orderdetails ord2
  ON ord1.odbcsn = ord2.odbcsn 
LEFT JOIN items itm ON ord1.oditnr = itm.imitnr
WHERE ord2.oditnr = '1022925'  
   AND ord2.odredt >= (CURDATE() - interval 60 day  + 0) 
   AND ord1.odbcsn = '11677'  
ORDER BY odredt desc ;


-- Updated this query
    SELECT ord1.oditnr, ord1.odredt, itm.imdesc  
    FROM orderdetails ord1
    LEFT JOIN orderdetails ord2
      ON ord1.odbcsn = ord2.odbcsn 
    LEFT JOIN items itm ON ord1.oditnr = itm.imitnr
    WHERE ord2.oditnr = '2521809'  
       AND ord2.odredt >= (CURDATE() - interval 60 day  + 0) 
       AND ord1.odbcsn = '11677'  
    ORDER BY odredt desc ;

更新:我调整了底部查询以将 INNER JOIN 更改为 LEFT JOIN。但是,与 OP 发布的查询不同,如果未找到 ord2.oditnr,此版本将返回一个空集 - 这从直觉上讲是有道理的 - 如果未找到订单号,则不返回任何行。如果没有某种子查询,就真的没有办法返回一个基于非的集合

至少,顶部查询与 OP 输出相匹配。

【讨论】:

恐怕内连接无法帮助找到不存在的记录。 此查询适用于转换 WHERE EXISTS。 我还想要一个查询,我可以使用任何项目编号来表示不存在。例如。客户 (11677) 实际购买了商品 (1025926),因此 NOT EXISTS 查询正确地不返回任何结果。 sqlfiddle.com/#!9/357b5/6

以上是关于将这些 DB2 SUBQUERY 重写为 Join的主要内容,如果未能解决你的问题,请参考以下文章

Mysql join with subquery join 使用相关名称

将JOIN查询重写为子查询,缺少行?

MySQL Left Join Subquery with *

LEFT JOIN 和 SUBQUERY 与空列 / null 作为结果

MySQL LEFT JOIN 或 WHERE IN SUBQUERY

带有 CASE 和 JOIN SUBQUERY 的 Oracle SQL 查询