Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Gabung kiri dengan nilai terdekat tanpa duplikat

Di bawah ini adalah solusi berbasis set menggunakan CTE dan fungsi windowing.

ranked_matches CTE memberikan peringkat kecocokan terdekat untuk setiap baris di TableA bersama dengan peringkat kecocokan terdekat untuk setiap baris di TableB , menggunakan index nilai sebagai pemutus ikatan.

best_matches CTE mengembalikan baris dari ranked_matches yang memiliki peringkat terbaik (nilai peringkat 1) untuk kedua peringkat.

Terakhir, kueri luar menggunakan LEFT JOIN dari TableA ke best_matches CTE untuk menyertakan TableA baris yang tidak diberi kecocokan terbaik karena kecocokan penutupan sudah ditetapkan.

Perhatikan bahwa ini tidak mengembalikan kecocokan untuk baris TabelA indeks 3 yang ditunjukkan dalam hasil sampel Anda. Yang paling cocok untuk baris ini adalah indeks TableB 3, selisih 83. Namun, baris TableB itu lebih cocok dengan baris TableA indeks 2, selisih 14 jadi sudah ditetapkan. Tolong jelaskan pertanyaan Anda jika ini bukan yang Anda inginkan. Saya pikir teknik ini dapat disesuaikan.

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:

Meskipun metode ini menggunakan CTE, rekursi tidak digunakan dan oleh karena itu tidak terbatas pada rekursi 32K. Mungkin ada ruang untuk perbaikan di sini dari perspektif kinerja.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. DEGREES() Contoh di SQL Server

  2. ADO.Net SQLCommand.ExecuteReader() melambat atau hang

  3. INSERT INTO dengan exec dengan beberapa set hasil

  4. Tentukan apakah Parameter SP memiliki Nilai Default di T-SQL

  5. SQL Server:Tingkat isolasi bocor di seluruh koneksi gabungan