Hieronder vindt u een set-gebaseerde oplossing die gebruikmaakt van CTE's en vensterfuncties.
De ranked_matches
CTE wijst voor elke rij in TableA
een rangorde toe die het meest overeenkomt met samen met een rangorde die het meest overeenkomt met elke rij in TableB
, met behulp van de index
waarde als tiebreak.
De best_matches
CTE retourneert rijen van ranked_matches
die de beste rang (rangwaarde 1) hebben voor beide ranglijsten.
Ten slotte gebruikt de buitenste query een LEFT JOIN
van TableA
naar de naar de best_matches
CTE om de TableA
. op te nemen rijen waaraan geen beste overeenkomst is toegewezen omdat de sluitovereenkomst al is toegewezen.
Houd er rekening mee dat dit geen overeenkomst oplevert voor de rij met index 3 TabelA die is aangegeven in uw voorbeeldresultaten. De sluitovereenkomst voor deze rij is TabelB-index 3, een verschil van 83. Die tabelB-rij komt echter beter overeen met de tabelA-index 2-rij, een verschil van 14, dus deze was al toegewezen. Gelieve uw vraag te verduidelijken als dit niet is wat u wilt. Ik denk dat deze techniek dienovereenkomstig kan worden aangepast.
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];
BEWERKEN:
Hoewel deze methode gebruik maakt van CTE's, wordt recursie niet gebruikt en is daarom niet beperkt tot 32K-recursies. Er kan hier echter ruimte zijn voor verbetering vanuit een prestatieperspectief.