Sql 将子选择转换为联接
我似乎明白,Join比sub-select更受欢迎。 我看不出如何将3个子选择变成连接 我的sub选择仅获取第一行 如果这不是冒犯性的SQL,我完全愿意就此置之不理 这是我的查询,是的,这些确实是表名和列名Sql 将子选择转换为联接,sql,db2-400,Sql,Db2 400,我似乎明白,Join比sub-select更受欢迎。 我看不出如何将3个子选择变成连接 我的sub选择仅获取第一行 如果这不是冒犯性的SQL,我完全愿意就此置之不理 这是我的查询,是的,这些确实是表名和列名 select x1.*, x2.KTNR, x3.J6NQ from (select D0HONB as HONB, D0HHNB as HHNB, ( select DHHHNB from ECDHREP
select x1.*, x2.KTNR, x3.J6NQ
from
(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,
(
select FIQ9NB
from DCFIREP
where FIQ7NB = D0Q7NB
AND FIBAEQ = D0ATEQ
and FISQCD = D0KNCD
and FIGZSZ in ('POS', 'ACT', 'MAN', 'HLD')
order by FIYCNB desc
FETCH FIRST 1 ROW ONLY
) as BL_Q9NB,
(
select AAKPNR
from C1AACPP
where AACEEQ = D0ATEQ and AARCCE = D0KNCD and AARDCE = D0KOCD
order by AAHMDT desc, AANENO desc
FETCH FIRST 1 ROW ONLY
) as NULL_KPNR
from ECD0REP
) as x1
left outer join (
select AAKPNR as null_kpnr, max(ABKTNR) as KTNR
from C1AACPP
left outer join C1ABCPP on AAKPNR = ABKPNR
group by AAKPNR
) as X2 on x1.NULL_KPNR = x2.null_KPNR
left outer join (
select ACKPNR as KPNR, count(*) as J6NQ
from C1ACCPP
WHERE ACJNDD = 'Y'
group by ACKPNR
) as X3 on x1.NULL_KPNR = x3.KPNR
您已经获得了相关子选择和嵌套表表达式(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 <...>
您要求DB做的是针对ECD0REP中读取的每一行,从ECDHREP中获取一行。如果您运气不好,数据库将不得不读取ECDHREP中的大量记录才能找到那一行。一般来说,考虑到相关的子查询,内部查询将需要读取<强>每个< /强>行。因此,如果外部有M行,内部有N行……那么您看到的是正在读取的MxN行
我以前见过这种情况,尤其是在IBMi上。因为这是一个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
。好的,你可以专注于CTE,找出需要做什么才能得到你想要的那一行。也许MAX(DHHHNB)
或MIN(DHHHNB)
会起作用。如果没有其他内容,您可以使用行数()
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个相关和常规子查询的查询……事实上,我看到一个查询必须分成两个,因为有两个多个子查询。DB对每条语句的限制为256条。您得到了相关子选择和嵌套表表达式(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 <...>
您要求DB做的是针对ECD0REP中读取的每一行,从ECDHREP中获取一行。如果您运气不好,数据库将不得不读取ECDHREP中的大量记录才能找到那一行。一般来说,考虑到相关的子查询,内部查询将需要读取<强>每个< /强>行。因此,如果外部有M行,内部有N行……那么您看到的是正在读取的MxN行
我以前见过这种情况,尤其是在IBMi上。因为这是一个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
。好的,你可以专注于CTE,找出需要做什么才能得到你想要的那一行。也许MAX(DHHHNB)
或MIN(DHHHNB)
会起作用。如果没有其他内容,您可以使用行数()
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个相关和常规子查询的查询……事实上,我看到一个查询必须分成两个,因为有两个多个子查询。DB对每条语句的限制为256。如果需要仅获取第一行
子句,我将不得不在这里与Charles不同。在这种情况下,您可能无法将这些子选项拉到CTE中,因为该CTE中只有一行。我怀疑您可以将外部子选择拉入CTE,但您仍然需要CTE中的子选择。既然没有分享,我就称之为个人偏好。顺便说一句,出于同样的原因,我认为将子选择拉入联接也不适用于您
子选择和CTE之间有什么区别
with mycte as (
select field1, field2
from mytable
where somecondition = true)
select *
from mycte
vs
这实际上只是个人偏好,尽管根据具体要求,CTE可以在SQL语句中多次使用,但在其他情况下,如问题中的fetch 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);
塞科