Nedan finns en uppsättningsbaserad lösning som använder CTE:er och fönsterfunktioner.
ranked_matches
CTE tilldelar en närmast matchningsrankning för varje rad i TableA
tillsammans med en närmast matchningsrankning för varje rad i TableB
, med hjälp av index
värde som oavgjort.
best_matches
CTE returnerar rader från ranked_matches
som har den bästa rankningen (rankvärde 1) för båda rankningarna.
Slutligen använder den yttre frågan en LEFT JOIN
från TableA
till till best_matches
CTE för att inkludera TableA
rader som inte tilldelats en bästa matchning på grund av att den avslutande matchen redan har tilldelats.
Observera att detta inte returnerar en matchning för index 3 TabellA rad som anges i dina exempelresultat. Den avslutande matchningen för den här raden är TabellB index 3, en skillnad på 83. Den tabellB-raden är emellertid en närmare matchning med TabellA-index 2-raden, en skillnad på 14 så den var redan tilldelad. Vänligen förtydliga din fråga om detta inte är vad du vill. Jag tror att den här tekniken kan anpassas därefter.
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];
EDIT:
Även om denna metod använder CTE, används inte rekursion och är därför inte begränsad till 32K-rekursioner. Det kan dock finnas utrymme för förbättringar här ur ett prestationsperspektiv.