我似乎明白Join更喜欢sub-select。 我无法看到如何将3个子选择转为连接。
我的子选择仅获取第一行
如果它不是令人反感的SQL,我完全愿意放弃它。
这是我的查询,是的,那些确实是表名和列名
for (var i of selectedRows) {
for (var j of deSelectedRows) {
if ( i.id === j.id ) {
selectedRows.splice(i, 1);
}
}
}
答案 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
谓词,但它远远不需要进行全表扫描。