SQL 语句之间的区别

Difference between SQL statements

我遇到了 SQLRPGLE 程序的两个版本,并看到代码发生了如下变化:

之前:

Exec Sql SELECT 'N' 
         INTO :APRFLG            
         FROM LG751F T1 
         INNER JOIN LG752F T2 
           ON T1.ISBOLN  =  T2.IDBOLN AND   
              T1.ISITNO  =  T2.IDMDNO 
        WHERE T2.IDVIN   =  :M_VIN AND      
              T1.ISAPRV  <> 'Y';            

之后:

Exec Sql SELECT case 
                  when T1.ISAPRV <> 'Y' then 'N'                        
                  else T1.ISAPRV                  
                end as APRFLG                          
         INTO :APRFLG                                  
         FROM LG751F T1                                
         join LG752F T2 
           ON T1.ISBOLN =  T2.IDBOLN AND   
              T1.ISITNO =  T2.IDMDNO       
        WHERE T2.IDVIN  =  :M_VIN AND                 
              T1.ISAPRV <> 'Y'                        
     group by T1.ISAPRV;                 

如果您发现这些代码的工作方式有何不同,能否告诉我?第二个 SQL 有一个组,应该是一个避免 -811 SQLCod 错误的修复。除此之外,大家有发现什么不同吗?

除了添加分组依据之外,我没有发现任何引人注目的区别,这将具有抑制可能已输出的任何重复行的效果。

看起来开发人员希望查询能够将其输出更改为有时是 Y 有时是 N,但忘记删除必须强制大小写始终为真的 WHERE 子句,因此它总是输出 N。 这种模式通常出现在原始报告包含一些规范,如 "don't include managers in the employee Sakarya report" 然后更改为 "actually we want to know if the employee is a manager or not" 时。 "where employee not equal manager" 变成了 "case when employee is manager then... else.." 但 where 子句需要删除才能生效

inner 关键字已从 join 语句中消失,但总体而言这也应该是一个非操作

它们都是 IMO 编码不佳的例子。

对 "remove duplicates" 的要求通常表明语句设计不当 and/or 数据库设计不当。

您似乎在进行存在性检查,在这种情况下,您应该使用 EXISTS 谓词。

select 'N' into :APRFLG
from sysibm.sysdummy1
where exists (select 1
              FROM LG751F T1 
                   INNER JOIN LG752F T2 
                     ON T1.ISBOLN  =  T2.IDBOLN    
                        AND T1.ISITNO  =  T2.IDMDNO 
              WHERE 
                T2.IDVIN   =  :M_VIN 
                AND T1.ISAPRV  <> 'Y');

就原来的两个语句而言,除了分组依据之外,唯一真正的区别是将列从 JOIN 子句移动到 WHERE 子句。但是,Db2 for i 中的查询引擎将等效地重写这两个语句并得出相同的计划;因为使用了内部连接。

EDIT : 正如 Mark 指出的那样,JOINWHERE 在两个 OP 的陈述中是相同的。但我会将上面的声明保留为仅供参考。

另一种选择是像这样使用 fetch first row only

Exec Sql 
  SELECT 'N' 
    INTO :APRFLG            
    FROM LG751F T1 
      JOIN LG752F T2 
        ON T1.ISBOLN  =  T2.IDBOLN AND   
           T1.ISITNO  =  T2.IDMDNO 
    WHERE T2.IDVIN   =  :M_VIN AND      
          T1.ISAPRV  <> 'Y'
    fetch first row only;

这更明显地表明您只需要一行而不是尝试使用分组,这需要时髦的 do nothing CASE 语句。但我确实喜欢 Charles 提供的 EXISTS 方法,因为这是真正的目标,并且 exists 使它 crystal 清晰。

如果您的领导坚持 GROUP BY,您也可以 GROUP BY 'N' 并且仍然省略 CASE 声明。