我希望得到一行与左外连接的'on'子句中的case表达式中的第一个匹配“when”相匹配,但是我得到 EVERY 中的行匹配。
互联网告诉我这是不可能的,一个案例将始终在第一次匹配时停止。
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'
如果两个条款都存在,我得到
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
如果我注释掉第1段时间,我只会得到第一行。 如果我注释掉第二个条款,我只会得到第二行 我不明白为什么它不会停留在匹配的第一个if子句?
答案 0 :(得分:1)
连接时,连接一侧的所有行都将根据连接另一侧的所有行进行评估。
您的案例陈述在第一场比赛时停止,对于任何一方的每对行。只是因为左侧的其中一行已经匹配了右侧的一行,并没有阻止它匹配右侧的另一行,使用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 :(得分:1)
这种情况会产生一组记录,这些记录与导致1的时间相匹配。要获得第一个匹配的记录,你可以做一个前n:
SELECT TOP 1 MILL_ORDER_NUMBER ...
一个分组可以让你在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
答案 2 :(得分:0)
这对你有用吗?
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'
我意识到有些parens是多余的,但为了保持一致而保留它们。我不是100%确定这是你所追求的,但是......
TOP 1将为您提供第一个结果(虽然没有ORDER BY子句,但是任意结果将是第一个)。
新的ON条款有点清洁,我认为代表了你的目标;如果不是,它至少应该更容易可视化和操纵。
我希望这会有所帮助。