sql >> Database teknologi >  >> RDS >> Sqlserver

Venstre sammenføjning med nærmeste værdi uden dubletter

Nedenfor er en sæt-baseret løsning, der bruger CTE'er og vinduesfunktioner.

ranked_matches CTE tildeler en tættest match-rangering for hver række i TableA sammen med en tættest match-rangering for hver række i TableB , ved hjælp af index værdi som uafgjort.

best_matches CTE returnerer rækker fra ranked_matches der har den bedste rang (rangværdi 1) for begge rangeringer.

Endelig bruger den ydre forespørgsel en LEFT JOIN fra TableA til til best_matches CTE for at inkludere TableA rækker, der ikke blev tildelt et bedste match, fordi det lukkede match allerede er tildelt.

Bemærk, at dette ikke returnerer et match for indeks 3 TabelA række angivet i dine prøveresultater. Det lukkede match for denne række er TabelB-indeks 3, en forskel på 83. Denne TabelB-række er imidlertid et tættere match med TabelA-indeks 2-rækken, en forskel på 14, så den var allerede tildelt. Afklar venligst dit spørgsmål, hvis det ikke er det, du ønsker. Jeg tror, ​​at denne teknik kan justeres i overensstemmelse hermed.

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:

Selvom denne metode bruger CTE'er, bruges rekursion ikke og er derfor ikke begrænset til 32K rekursioner. Der kan dog være plads til forbedring her set fra et præstationsperspektiv.



  1. Kan ikke indsætte værdi som den er - har brug for svar for enhver DB - Oracle, SQL Server, MySql osv.

  2. Entity Relationship Model for studerende / rådgiver ansøgning

  3. PostgreSQL:Find sætninger tættest på en given sætning

  4. Gå til postgresql LIKE-forespørgsel