sql >> Databáze >  >> RDS >> Sqlserver

Levé spojení s nejbližší hodnotou bez duplicit

Níže je řešení založené na sadě pomocí CTE a funkcí oken.

ranked_matches CTE přiřadí každému řádku v TableA nejbližší hodnocení shody spolu s nejbližším hodnocením shody pro každý řádek v TableB pomocí index hodnotu jako nerozhodný výsledek.

best_matches CTE vrací řádky z ranked_matches které mají nejlepší hodnocení (hodnota pořadí 1) pro obě hodnocení.

Nakonec vnější dotaz používá LEFT JOIN z TableA na best_matches CTE zahrnout TableA řádky, kterým nebyla přiřazena nejlepší shoda, protože už byla přiřazena závěrečná shoda.

Všimněte si, že to nevrací shodu pro řádek tabulky A indexu 3 uvedený ve výsledcích vzorku. Nejbližší shoda pro tento řádek je index TableB 3, rozdíl 83. Tento řádek TableB se však blíže shoduje s řádkem indexu TableA 2, rozdíl 14, takže byl již přiřazen. Prosím, upřesněte svou otázku, pokud to není to, co chcete. Myslím, že tuto techniku ​​lze odpovídajícím způsobem upravit.

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];

UPRAVIT:

Přestože tato metoda používá CTE, rekurze se nepoužívá, a proto není omezena na 32K rekurze. Zde však může být prostor pro zlepšení z hlediska výkonu.



  1. Jak získat řádky, které mají součet rovný dané hodnotě

  2. Jaký je rozdíl mezi VARCHAR a NVARCHAR na SQL serveru - SQL Server / T-SQL výukový program, část 32

  3. jak zkombinovat tabulky se vztahem 1 až mnoho do 1 řádku záznamu

  4. Dotaz na získání 2. a 3. záznamu z tabulky