По-долу е базирано на набор решение, използващо CTE и функции за прозорци.
ranked_matches
CTE присвоява ранг на най-близкото съвпадение за всеки ред в TableA
заедно с ранга на най-близкото съвпадение за всеки ред в TableB
, използвайки index
стойност като прекъсвач на вратовръзка.
best_matches
CTE връща редове от ranked_matches
които имат най-добър ранг (стойност на ранг 1) и за двете класации.
И накрая, външната заявка използва LEFT JOIN
от TableA
към към best_matches
CTE за включване на TableA
редове, на които не е присвоено най-добро съвпадение поради вече зададеното затварящо съвпадение.
Обърнете внимание, че това не връща съвпадение за реда с индекс 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 рекурсии. Може обаче да има място за подобрение от гледна точка на производителността.