簡體   English   中英

SQL-Server左外連接時,情況在第一時間不停止

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM