Di seguito è riportata una soluzione basata su set che utilizza CTE e funzioni di windowing.
Le ranked_matches
CTE assegna un grado di corrispondenza più vicino per ogni riga in TableA
insieme a un grado di corrispondenza più vicino per ogni riga in TableB
, utilizzando l'index
valore come spareggio.
I best_matches
CTE restituisce le righe da ranked_matches
che hanno il miglior rank (valore 1) per entrambe le classifiche.
Infine, la query esterna utilizza un LEFT JOIN
da TableA
al best_matches
CTE per includere la TableA
righe a cui non è stata assegnata una corrispondenza migliore a causa della corrispondenza di chiusura già assegnata.
Si noti che questo non restituisce una corrispondenza per la riga dell'indice 3 TableA indicata nei risultati di esempio. La corrispondenza di chiusura per questa riga è l'indice TableB 3, una differenza di 83. Tuttavia, quella riga TableB è una corrispondenza più vicina alla riga dell'indice TableA 2, una differenza di 14, quindi era già stata assegnata. Per favore chiarisci la tua domanda se questo non è quello che vuoi. Penso che questa tecnica possa essere modificata di conseguenza.
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];
MODIFICA:
Sebbene questo metodo utilizzi CTE, la ricorsione non viene utilizzata e pertanto non è limitata alle ricorsioni a 32 KB. Tuttavia, potrebbe esserci spazio per miglioramenti qui dal punto di vista delle prestazioni.