我必须将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相等,然后只考虑第一个匹配算法留下的那些,以便通过INDEX匹配它们。这就是错误预期INDEX与BBB匹配的AAA(已经与另一个BBB匹配),实际上必须与另一个非CODE匹配项进行INDEX匹配,在这种情况下DDD。
答案 0 :(得分: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
答案 1 :(得分: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
答案 2 :(得分: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
答案 3 :(得分: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