[英]SQL-Server left outer join with case not stopping at first when
我想獲得與左外部聯接的“ on”子句中的case表達式中的第一個匹配“ when”匹配的行,但是當匹配時,我會從“ 每個”中獲取行。
互聯網告訴我這是不可能的,案件總是會在第一次匹配時停止。
SELECT MILL_ORDER_NUMBER
,SHORTY_NAME
,PRIMARY_DEST
,ALT_DESTINATION
,CB.CDE_CNSUM_LOC as CB4V_CNSUM_LOC
,CB.CDE_DEST
,CB.NAM_CUST_SHTY
FROM HLFOR01A OA
left outer join (select CDE_CNSUM_LOC, CDE_DEST, NAM_CUST_SHTY from CSAR_CB4V0023) CB
on case
when ((OA.SHORTY_NAME = CB.NAM_CUST_SHTY) and (substring(OA.PRIMARY_DEST,1,1) < 'A') and (OA.PRIMARY_DEST = CB.CDE_DEST)) then 1
when ((OA.SHORTY_NAME = CB.NAM_CUST_SHTY) and (CB.CDE_DEST = (select min(dd.CDE_DEST) from CSAR_CB4V0023 dd where dd.NAM_CUST_SHTY = OA.SHORTY_NAME))) then 1
else 0 end = 1
where MILL_ORDER_NUMBER = '84220631'
如果兩個when子句都存在,我得到
MILL_ORDER_NUMBER SHORTY_NAME PRIMARY_DEST ALT_DESTINATION CB4V_CNSUM_LOC CDE_DEST NAM_CUST_SHTY
84220631 CMPNY1 5U 1641 00 CMPNY1 <-- matches 2nd when clause
84220631 CMPNY1 5U 1627 5U CMPNY1 <-- matches 1st when clause
如果我注釋掉第一個when子句,那么我只會得到第一行。 如果我注釋掉第二個when子句,那么我只會得到第二行。
我不明白為什么它不止於匹配的第一個when子句?
連接時,將針對連接另一側的所有行評估連接一側的所有行。
您的case語句將在第一個匹配項處停止(對於每一行的每一對行)。 僅僅因為左邊的某一行已與右邊的某行匹配,並不會阻止您使用case語句中的任一情況匹配右邊的另一行,因為每對都獨立於任何現有匹配進行求值。 您的case語句實際上等效於,但效率低於:
on OA.SHORTY_NAME = CB.NAM_CUST_SHTY
and ((substring(OA.PRIMARY_DEST,1,1) < 'A' and OA.PRIMARY_DEST = CB.CDE_DEST)
or (CB.CDE_DEST = (select min(dd.CDE_DEST) from CSAR_CB4V0023 dd where dd.NAM_CUST_SHTY = OA.SHORTY_NAME))
可以將其視為嵌套在另一個for循環中的for循環,在每對可能的行對上執行case語句。
DECLARE @Table (MILL_ORDER_NUMBER {type}, SHORTY_NAME {type}, PRIMARY_DEST {type}, ALT_DESTINATION {type}, CB4V_CNSUM_LOC {type}, CDE_DEST {type}, NAM_CUST_SHTY {type})
INSERT INTO @Table (MILL_ORDER_NUMBER ,SHORTY_NAME ,PRIMARY_DEST ,ALT_DESTINATION ,CB4V_CNSUM_LOC, CDE_DEST, NAM_CUST_SHTY)
SELECT MILL_ORDER_NUMBER, SHORTY_NAME, PRIMARY_DEST, ALT_DESTINATION, CB.CDE_CNSUM_LOC, CB.CDE_DEST, CB.NAM_CUST_SHTY
FROM HLFOR01A OA
JOIN (select CDE_CNSUM_LOC, CDE_DEST, NAM_CUST_SHTY from CSAR_CB4V0023) CB
on ((OA.SHORTY_NAME = CB.NAM_CUST_SHTY) and (CB.CDE_DEST = (select min(dd.CDE_DEST) from CSAR_CB4V0023 dd where dd.NAM_CUST_SHTY = OA.SHORTY_NAME)))
where MILL_ORDER_NUMBER = '84220631'
INSERT INTO @Table (MILL_ORDER_NUMBER ,SHORTY_NAME ,PRIMARY_DEST ,ALT_DESTINATION ,CB4V_CNSUM_LOC, CDE_DEST, NAM_CUST_SHTY)
SELECT MILL_ORDER_NUMBER, SHORTY_NAME, PRIMARY_DEST, ALT_DESTINATION, CB.CDE_CNSUM_LOC, CB.CDE_DEST, CB.NAM_CUST_SHTY
FROM HLFOR01A OA
JOIN (select CDE_CNSUM_LOC, CDE_DEST, NAM_CUST_SHTY from CSAR_CB4V0023) CB
on ((OA.SHORTY_NAME = CB.NAM_CUST_SHTY) and (substring(OA.PRIMARY_DEST,1,1) < 'A') and (OA.PRIMARY_DEST = CB.CDE_DEST))
where MILL_ORDER_NUMBER = '84220631' AND NOT EXISTS (SELECT top 1 1 FROM @table t where t.MILL_ORDER_NUMBER=OA.MILL_ORDER_NUMBER)
INSERT INTO @Table (MILL_ORDER_NUMBER ,SHORTY_NAME ,PRIMARY_DEST ,ALT_DESTINATION)
SELECT MILL_ORDER_NUMBER, SHORTY_NAME, PRIMARY_DEST, ALT_DESTINATION
FROM HLFOR01A OA
where MILL_ORDER_NUMBER = '84220631' AND NOT EXISTS (SELECT top 1 1 FROM @table t where t.MILL_ORDER_NUMBER=OA.MILL_ORDER_NUMBER)
SELECT MILL_ORDER_NUMBER ,SHORTY_NAME ,PRIMARY_DEST ,ALT_DESTINATION ,CB4V_CNSUM_LOC, CDE_DEST, NAM_CUST_SHTY FROM @Table
這種情況將產生一組記錄,這些記錄與將導致結果為1的when之一匹配。要獲取第一個匹配記錄,可以執行前n個:
SELECT TOP 1 MILL_ORDER_NUMBER ...
分組依據可以使您下降到1個結果行,並在CB4V_CNSUM_LOC,CB.CDE_DEST,CB.NAM_CUST_SHTY上具有最小值或最大值,但是您可能將它們與多個記錄混合在一起,所以這可能不是您想要的。
對第一個選項的調整將是“加權”案件的每個案件,這樣您將獲得與第一個案件(如果存在)匹配的行:
SELECT TOP 1 MILL_ORDER_NUMBER ...
...
ORDER BY
case
when ((OA.SHORTY_NAME = CB.NAM_CUST_SHTY) and (substring(OA.PRIMARY_DEST,1,1) < 'A') and (OA.PRIMARY_DEST = CB.CDE_DEST))
then 1
when ((OA.SHORTY_NAME = CB.NAM_CUST_SHTY) and (CB.CDE_DEST = (select min(dd.CDE_DEST) from CSAR_CB4V0023 dd where dd.NAM_CUST_SHTY = OA.SHORTY_NAME)))
then 2
else 99 end
這對您有用嗎?
SELECT TOP 1 MILL_ORDER_NUMBER
,SHORTY_NAME
,PRIMARY_DEST
,ALT_DESTINATION
,CB.CDE_CNSUM_LOC as CB4V_CNSUM_LOC
,CB.CDE_DEST
,CB.NAM_CUST_SHTY
FROM HLFOR01A OA
left outer join (select CDE_CNSUM_LOC, CDE_DEST, NAM_CUST_SHTY from CSAR_CB4V0023) CB on
((OA.SHORTY_NAME = CB.NAM_CUST_SHTY) and (substring(OA.PRIMARY_DEST,1,1) < 'A') and (OA.PRIMARY_DEST = CB.CDE_DEST))
or
((OA.SHORTY_NAME = CB.NAM_CUST_SHTY) and (CB.CDE_DEST = (select min(dd.CDE_DEST) from CSAR_CB4V0023 dd where dd.NAM_CUST_SHTY = OA.SHORTY_NAME)))
where MILL_ORDER_NUMBER = '84220631'
我知道有些括號是多余的,但為了保持一致而保留它們。 我不是100%確定這就是您要追求的,但是...
TOP 1將為您帶來第一個結果(盡管沒有ORDER BY子句,將哪個結果作為第一是任意的)。
新的ON子句更加簡潔,我認為它代表了您的目標。 如果不是這樣,則至少應該更容易觀察和操作。
我希望這有幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.