A continuación se muestra una solución basada en conjuntos que utiliza CTE y funciones de ventanas.
Los ranked_matches
CTE asigna un rango de coincidencia más cercano para cada fila en TableA
junto con una clasificación de coincidencia más cercana para cada fila en TableB
, utilizando el index
valor como desempate.
Las best_matches
CTE devuelve filas de ranked_matches
que tienen la mejor clasificación (valor de clasificación 1) para ambas clasificaciones.
Finalmente, la consulta externa usa un LEFT JOIN
de TableA
a las best_matches
CTE para incluir la TableA
filas a las que no se les asignó una mejor coincidencia debido a que ya se asignó la coincidencia más cercana.
Tenga en cuenta que esto no devuelve una coincidencia para la fila del índice 3 TableA indicada en los resultados de su muestra. La coincidencia más cercana para esta fila es el índice 3 de TableB, una diferencia de 83. Sin embargo, esa fila de TableB es una coincidencia más cercana a la fila de índice 2 de TableA, una diferencia de 14, por lo que ya estaba asignada. Por favor aclare su pregunta si esto no es lo que quiere. Creo que esta técnica se puede modificar en consecuencia.
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];
EDITAR:
Aunque este método usa CTE, la recursión no se usa y, por lo tanto, no se limita a recursiones de 32K. Sin embargo, puede haber margen de mejora aquí desde una perspectiva de rendimiento.