以下は、CTE とウィンドウ関数を使用したセットベースのソリューションです。
ranked_matches
CTE は、TableA
の各行に最も近い一致ランクを割り当てます TableB
の各行の最も近い一致ランクとともに 、 index
を使用 タイブレーカーとしての価値。
best_matches
CTE は ranked_matches
から行を返します 両方のランキングで最高のランク (ランク値 1) を持つもの。
最後に、外側のクエリは LEFT JOIN
を使用します TableA
から best_matches
へ TableA
を含める CTE 近似一致がすでに割り当てられているため、最適一致が割り当てられなかった行。
これは、サンプル結果に示されているインデックス 3 TableA 行との一致を返さないことに注意してください。この行の最も近い一致は TableB インデックス 3 で、83 の差があります。しかし、その TableB 行は TableA インデックス 2 行とより近く一致し、14 の差があるため、既に割り当てられています。これがあなたが望むものでない場合は、質問を明確にしてください。この手法はそれに応じて微調整できると思います。
CREATE TABLE dbo.TableA(
[index] int NOT NULL
CONSTRAINT PK_TableA PRIMARY KEY
, value int
);
CREATE TABLE dbo.TableB(
[index] int NOT NULL
CONSTRAINT PK_TableB PRIMARY KEY
, value int
);
INSERT INTO dbo.TableA
( [index], value )
VALUES ( 1, 123 ),
( 2, 245 ),
( 3, 342 ),
( 4, 456 ),
( 5, 608 );
INSERT INTO dbo.TableB
( [index], value )
VALUES ( 1, 152 ),
( 2, 159 ),
( 3, 259 );
WITH
ranked_matches AS (
SELECT
a.[index] AS a_index
, a.value AS a_value
, b.[index] b_index
, b.value AS b_value
, RANK() OVER(PARTITION BY a.[index] ORDER BY ABS(a.Value - b.value), b.[index]) AS a_match_rank
, RANK() OVER(PARTITION BY b.[index] ORDER BY ABS(a.Value - b.value), a.[index]) AS b_match_rank
FROM dbo.TableA AS a
CROSS JOIN dbo.TableB AS b
)
, best_matches AS (
SELECT
a_index
, a_value
, b_index
, b_value
FROM ranked_matches
WHERE
a_match_rank = 1
AND b_match_rank= 1
)
SELECT
TableA.[index] AS a_index
, TableA.value AS a_value
, best_matches.b_index
, best_matches.b_value
FROM dbo.TableA
LEFT JOIN best_matches ON
best_matches.a_index = TableA.[index]
ORDER BY
TableA.[index];
編集:
このメソッドは CTE を使用しますが、再帰は使用されないため、32K 再帰に限定されません。ただし、パフォーマンスの観点からは、ここに改善の余地があるかもしれません。