2011-06-24 23 views
1

私はTABLE1の各レコードをTABLE2の多くとも1つのレコードとマッチさせる必要があります。 (CODEの等価性)と貧弱なもの(CODEの等価性がない場合は、CODEでソートしてインデックスで照合してみましょう)を照合するより良い方法があります。JOINの優先順位は?

のは、これを行うコードは次のようになりますことを第一近似として想定してみましょう:

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 

ここに難しさがあります:私は2つの条件が一致しているにもかかわらず、可能であれば、第1のものを第2のものより優先させなければならず、第2のものはが最初のものに失敗した場合にのみと評価されなければならない。

指名手配結果ビーイング:

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 

そしてもちろん、私は、好ましくは、いくつかの-のステップのスクリプトを避けるために、オール・イン・ワンの問合せこの挙動を得るだろう、与えられたもの:

  • あなたはまったく異なった質問を自由に提案することができます:上記は一般的なアイデアを説明するためだけにありましたが、それはニーズに合わないことは明らかです。したがって、その構造を保存しようとする必要はありません。

  • オールインワン・クエリー・マッチングを実行したいのと比べて、パフォーマンスは本当に気にしません。サブクエリーが必要な場合は、行こう! ;-)

あなたのご意見をお待ちしています! :-)

EDIT:

私は今修正と深く正確な答えとして考えることができるものに変更された私のOPに強いエラーをしました。期待された結果は正しくありませんでした。私の最も謙虚な謝罪。 :-(

アイデアは次のとおりです:CODEの等価性にできるだけ一致させてから、この最初の一致アルゴリズムによって残されたものだけをINDEXでマッチさせることを考えてください。そのため、INDEX-

+0

2番目のサブクエリはTable2ではなくTable1であるべきですか? –

+0

申し訳ありませんが、もちろんそうです。私はOPを修正しました。 – Ssithra

+0

@Ssithra: 'CODE'の2つのフィールドにUNIQUE制約がありますか? –

答えて

0

[OK]を、私はそれを得ました。 私は誰かのためにそこに興味があるかもしれない場合のために答えを掲示する。 それは最終的なニーズに応じて調整することができますが、アイデアはそこにあります(私はフィールド/定数の名前を少し変更しました。実際の人生の名前にもっと近く、解決策を見つけるのに役立ちました。 )。

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

あなたのテストデータと期待される結果が与えられれば、これは正しい結果を与えます(実際には別のBBBとCODEマッチするBBBと一致します)。 。

;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