将subselect转换为连接

时间:2018-03-29 13:28:20

标签: sql db2-400

我似乎明白Join更喜欢sub-select。 我无法看到如何将3个子选择转为连接。

我的子选择仅获取第一行

如果它不是令人反感的SQL,我完全愿意放弃它。

这是我的查询,是的,那些确实是表名和列名

for  (var  i  of selectedRows) {
    for  (var  j  of deSelectedRows) {
      if  ( i.id  ===  j.id ) {
        selectedRows.splice(i,  1);
      }
    }
  }

2 个答案:

答案 0 :(得分:1)

您有相关子选择和嵌套表表达式(NTE)的组合。

就个人而言,如果我不得不维持它,我会称它为冒犯性的。 ;)

考虑常见的表格表达式&加入...没有你的数据和tabvle结构,我不能给你真实的陈述,但一般的形式看起来像

with 
   STC_HHNB as (
     select DHHHNB, DHAOEQ, DHJRCD, DHEJDT
      from ECDHREP )
,  BL_Q9NB as ( <....>
               where FIGZSZ in ('POS', 'ACT', 'MAN', 'HLD'))
<...>
select <...>
from stc_hhb
     join blq9nb on <...>

支持CTE而不是NTE的两个重要原因...... CTE的结果可以重复使用此外,使用CTE逐步建立一个语句也很容易。

通过重复使用,我的意思是你可以拥有

with 
  cte1 as (<...>)
  , cte2 as (select <...> from cte1 join <...>)
  , cte3 as (select <...> from cte1 join <...>)
  , cte4 as (select <...> from cte2 join cte3 on <...>)
select * from cte4;

优化器可以选择为cte1构建临时结果集并多次使用它。从建筑的角度来看,你可以看到我在每个前面的cte上建造。

这是一篇好文章 https://www.mcpressonline.com/programming/sql/simplify-sql-qwithq-common-table-expressions

修改

让我们深入研究您的第一个相关子查询。

select D0HONB as HONB, D0HHNB as HHNB, 
      (
          select DHHHNB 
          from ECDHREP 
          where DHAOEQ = D0ATEQ and DHJRCD = D0KNCD 
          order by DHEJDT desc 
          FETCH FIRST 1 ROW ONLY
        ) as STC_HHNB
from ECD0REP

你要求DB做的是读取ECD0REP中读取的每一行,然后从ECDHREP获取一行。如果你运气不好,数据库必须在ECDHREP中读取大量记录才能找到这一行。通常,考虑使用相关子查询,内部查询需要读取每个行。因此,如果外部有M行,内部有N行......那么您正在查看正在读取的MxN行。

我以前见过这个,特别是在IBM i上。这就是RPG开发人员如何做到这一点

read ECD0REP;
dow not %eof(ECD0REP);
  //need to get DHHHNB from ECDHREP 
  chain (D0ATEQ, D0KNCD) ECDHREP;
  STC_HHNB = DHHHNB;
  read ECD0REP;
enddo;

但这不是在SQL中实现它的方法。 SQL(应该是)基于设置。

所以你需要做的是考虑如何从ECDHREP中选择一组记录,这些记录将匹配你想要的ECD0REP记录集。

with cte1 as (
  select DHHHNB, DHAOEQ, DHJRCD
  from ECDHREP
)
select D0HONB as HONB
     , D0HHNB as HHNB
     , DHHHBN as STC_HHNB
from ECD0REP join cte1 
      on DHAOEQ = D0ATEQ and DHJRCD = D0KNCD

现在也许这不太正确。也许ECDHREP中有多行具有相同的值(DHAOEQ,DHJRCD);因此,您需要相关子查询中的FETCH FIRST。很好,你可以专注于CTE,并找出需要做什么来获得你想要的那一行。也许MAX(DHHHNB)MIN(DHHHNB)可行。如果不出意外,您可以使用ROW_NUMBER()选出一行......

with cte1 as (
  select DHHHNB, DHAOEQ, DHJRCD
         , row_number() over(partition by DHAOEQ, DHJRCD
                             order by DHAOEQ, DHJRCD)
            as rowNbr  
  from ECDHREP
), cte2 as (
   select DHHHNB, DHAOEQ, DHJRCD
     from cte1
    where rowNbr = 1
)
select D0HONB as HONB
     , D0HHNB as HHNB
     , DHHHBN as STC_HHNB
from ECD0REP join cte2
      on DHAOEQ = D0ATEQ and DHJRCD = D0KNCD

现在,您正在处理多组记录,将它们连接在一起以获得最终结果。

更糟糕的是,数据库必须读取M + N条记录。

这不是关于表现,而是关于集思考。

当使用相关子查询的简单语句时,优化器可能会将其重新写入连接。

但最好尽可能编写最好的代码,而不是希望优化器能够纠正它。

我已经看到并重写了100个相关&amp;常规子查询....实际上我已经看到一个必须被分成2的查询,因为有两个子查询。数据库的每个语句限制为256。

答案 1 :(得分:1)

如果FETCH FIRST 1 ROW ONLY条款是必要的话,我将不得不在这里与查尔斯不同。在这种情况下,您可能无法将这些子选择拉出到CTE中,因为CTE中只有一行。我怀疑你可以将外部子选择拉入CTE,但你仍然需要在CTE中进行子选择。由于似乎没有共享,我会称之为个人偏好。顺便说一句,我不认为将子选项拉入连接也不会对你有用,在这种情况下,出于同样的原因。

子选择和CTE有什么区别?

with mycte as (
  select field1, field2 
  from mytable
  where somecondition = true)
select * 
from mycte

VS

select * 
from (select field1, field2 
      from mytable
      where somecondition = true) a

这实际上只是个人偏好,但根据具体要求,CTE可以在SQL语句中多次使用,但在其他情况下,如子句中的FETCT FIRST子句,子选择会更正确。你的问题。

修改
我们来看看第一个子查询。使用适当的索引:

(
    select DHHHNB 
    from ECDHREP 
    where DHAOEQ = D0ATEQ and DHJRCD = D0KNCD 
    order by DHEJDT desc 
    FETCH FIRST 1 ROW ONLY
) as STC_HHNB,

只需读取输出集中每行一条记录。我认为这不是非常繁重。对于第三个相关的子查询也是如此。

第一个相关子查询的索引是:

create index ECDHREP_X1 
  on ECDHREP (DHAOEQ, DHJRCD, DHEJDT);

第二个相关的子查询可能需要每行多次读取,这只是因为IN谓词,但它远远不需要进行全表扫描。