2011-06-24 58 views
1

我必須將TABLE1中的每條記錄與TABLE2中的最多1條記錄進行匹配。 有一個更好的方法來匹配(CODE相等)和一個窮人(在沒有CODE相等的情況下,讓我們按CODE排序並按索引匹配)。加入已批准的標準嗎?

讓我們假設作爲第一近似,該代碼這樣做可能是這樣的:

SELECT 
TABLE1.CODE AS CODE1, 
TABLE2.CODE AS CODE2 
FROM 
(SELECT ROW_NUMBER() OVER(ORDER BY CODE) INDEX, CODE FROM TABLE1) T1 
LEFT JOIN 
(SELECT ROW_NUMBER() OVER(ORDER BY CODE) INDEX, CODE FROM TABLE2) T2 
ON 
(T1.CODE=T2.CODE) --CODE equality 
OR 
(T1.INDEX=T2.INDEX) --CODE equality 

讓我們考慮這些表:

TABLE1 TABLE2 
+------+ +------+ 
| CODE | | CODE | 
+------+ +------+ 
| AAA | | BBB | 
| BBB | | CCC | 
| CCC | | DDD | 
+------+ +------+ 

結果將是:

CODE1 CODE2 
----- ----- 
AAA BBB -> matched because of INDEX equality 
BBB BBB -> matched because of CODE equality 
BBB CCC -> matched because of INDEX equality 
CCC CCC -> matched because of CODE equality 
CCC DDD -> matched because of INDEX equality 

難度:我想表達這樣一個觀點,儘管有兩種匹配條件如果可能,第一個必須優先於第二個,並且第二個必須評估當且僅當第一個失敗時

的通緝的結果是:

CODE1 CODE2 
----- ----- 
AAA DDD -> matched because of INDEX equality between the cast-off records not able to match better 
       (corrected from the previous version where AAA was said to match expectedly with BBB) 
BBB BBB -> matched thanks to CODE equality, no need to match on INDEX 
CCC CCC -> matched thanks to CODE equality, no need to match on INDEX 

當然,我將優選獲得此行爲的所有功能於一身的查詢,以避免幾個步驟的腳本,因爲:

  • 你可以隨意提出一個完全不同的問題:上面的問題只是爲了說明總體思路,但很明顯它不符合需求。所以,不需要嘗試保留它的結構。

  • 與希望執行全功能於一身的查詢匹配相比,我並不在意性能。如果需要子查詢,讓我們開始吧! ;-)

渴望閱讀您的建議! :-)

編輯:

我改變了我的OP強大的錯誤,現在已經更正,深入改變什麼可以被看作是一個準確的答案。預期的結果是不正確的。我最謙卑的道歉。 :-(

這個想法是:儘可能地匹配CODE相等,然後只考慮那些被第一個匹配算法留下的匹配它們的索引,這就是爲什麼AAA錯誤地被期望INDEX-與BBB(已與另一個BBB進行CODE匹配)相匹配,必須事實上與其他非CODE匹配項目INDEX匹配,在這種情況下,DDD。

+0

您的第二個子查詢應該針對Table2而不是Table1? –

+0

對不起,當然是。我糾正了OP。 – Ssithra

+0

@Sithithra:這兩個字段'CODE'是否有一個UNIQUE約束? –

回答

0

好吧,我知道了。 我發佈了答案,以防其他人對此感興趣。 它可以根據最終的需求進行調整,但這個想法是存在的(我稍微改變了字段/常量的名稱:它更接近真實姓名並幫助我找到解決方案,否則它會過於理論化)。

declare @uc table(cod_uc varchar(3)) 
declare @cnt table(cod_cnt varchar(3)) 

insert into @uc values('a') 
insert into @uc values('b') 
insert into @uc values('c') 
insert into @cnt values('b') 
insert into @cnt values('c') 
insert into @cnt values('d') 
insert into @cnt values('e') 

;with codematchings(cod_uc,cod_cnt) 
as 
(a 
    select uc.cod_uc, cnt.cod_cnt 
    from 
    @uc uc full outer join @cnt cnt on uc.cod_uc=cnt.cod_cnt 
), 
orders(cod_uc,order_uc,cod_cnt,order_cnt) 
as 
(
    select cod_uc,row_number() over(order by isnull(cod_uc,'zzzz')) order_uc, cod_cnt,row_number() over(order by isnull(cod_cnt,'zzzz')) order_cnt from codematchings where cod_uc is null or cod_cnt is null 
) 
select codematchings.*, 
case 
when codematchings.cod_uc is null then orders2.cod_uc 
when codematchings.cod_cnt is null then orders2.cod_cnt 
else codematchings.cod_uc 
end matched_with 
from codematchings 
left outer join orders orders1 
on codematchings.cod_uc is null and orders1.cod_cnt=codematchings.cod_cnt or codematchings.cod_cnt is null and orders1.cod_uc=codematchings.cod_uc 
left outer join orders orders2 
on codematchings.cod_uc is null and orders2.order_uc=orders1.order_cnt or codematchings.cod_cnt is null and orders2.order_cnt=orders1.order_uc 

結果:

cod_uc cod_cnt matched_with 
------ ------- ------------ 
A  NULL D 
B  B  B 
C  C  C 
NULL D  A 
NULL E  NULL 
1

根據您的測試數據和預期結果,這會給出正確的結果。

;WITH T1 (row_id, code) AS (SELECT ROW_NUMBER() OVER (ORDER BY code) AS row_id, code FROM My_Table_1), 
    T2 (row_id, code) AS (SELECT ROW_NUMBER() OVER (ORDER BY code) AS row_id, code FROM My_Table_2) 
SELECT 
    T1.code, 
    COALESCE(T2.code, T3.code) 
FROM 
    T1 
LEFT OUTER JOIN T2 ON T2.code = T1.code 
LEFT OUTER JOIN T2 AS T3 ON T2.row_id IS NULL AND T3.row_id = T1.row_id 
0

我試圖在Oracle但這個想法是在這裏:

with t1 as (select 1 id,'AAA' col from dual union all 
      select 2, 'BBB'  from dual union all 
      select 3, 'CCC'  from dual), 
    t2 as (select 1 id,'BBB' col from dual union all 
      select 2, 'CCC'  from dual union all 
      select 3, 'DDD'  from dual) 
--- 
SELECT t1.col col1, t2.col col2 
    FROM t1, t2 
WHERE (t1.id = t2.id OR t1.col = t2.col) 
    AND (t2.id = 1 OR t1.col = t2.col) 

結果:

COL1 COL2 
--- --- 
AAA BBB 
BBB BBB 
CCC CCC 
0

初始化數據:

; WITH 

    T1 (CODE) AS 
    (SELECT 'AAA' CODE UNION 
    SELECT 'BBB'  UNION 
    SELECT 'CCC' 
) 
, T2 (CODE) AS 
    (SELECT 'BBB' CODE UNION 
    SELECT 'CCC'  UNION 
    SELECT 'DDD' 
) 

幫助表:

, FULLT (code1, code2) AS 
    (SELECT T1.CODE AS code1 
      , T2.CODE AS code2 
    FROM T1 
     FULL OUTER JOIN T2 
     ON T1.CODE = T2.CODE 
    ) 
, INNERT (code1, code2) AS 
    (SELECT code1 
      , code2 
    FROM FULLT 
    WHERE code1 = code2 
    ) 
, LEFTT (code1, rn) AS 
    (SELECT code1 
      , ROW_NUMBER() OVER(ORDER BY code1) AS rn 
    FROM FULLT 
    WHERE code2 IS NULL 
    ) 
, RIGHTT (code2, rn) AS 
    (SELECT code2 
      , ROW_NUMBER() OVER(ORDER BY code2) AS rn 
    FROM FULLT 
    WHERE code1 IS NULL 
    ) 

最終查詢:

SELECT code1    
     , code2 
    FROM INNERT 

UNION ALL 

    SELECT code1 
     , code2 
    FROM LEFTT 
    JOIN RIGHTT 
     ON LEFTT.rn = RIGHTT.rn 

ORDER BY code1 
     , code2