sql >> データベース >  >> RDS >> Sqlserver

重複のない最も近い値との左結合

    以下は、CTE とウィンドウ関数を使用したセットベースのソリューションです。

    ranked_matches CTE は、TableA の各行に最も近い一致ランクを割り当てます TableB の各行の最も近い一致ランクとともに 、 index を使用 タイブレーカーとしての価値。

    best_matches CTE は ranked_matches から行を返します 両方のランキングで最高のランク (ランク値 1) を持つもの。

    最後に、外側のクエリは LEFT JOIN を使用します TableA から best_matchesTableA を含める CTE 近似一致がすでに割り当てられているため、最適一致が割り当てられなかった行。

    これは、サンプル結果に示されているインデックス 3 TableA 行との一致を返さないことに注意してください。この行の最も近い一致は TableB インデックス 3 で、83 の差があります。しかし、その TableB 行は TableA インデックス 2 行とより近く一致し、14 の差があるため、既に割り当てられています。これがあなたが望むものでない場合は、質問を明確にしてください。この手法はそれに応じて微調整できると思います。

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

    編集:

    このメソッドは CTE を使用しますが、再帰は使用されないため、32K 再帰に限定されません。ただし、パフォーマンスの観点からは、ここに改善の余地があるかもしれません。



    1. SELECT ... FOR XML PATH('')、1,1)の意味は何ですか?

    2. SQLiteのPRAGMAtable_list

    3. 最も単純なMySQLクエリがfalseを返す理由をデバッグするにはどうすればよいですか?

    4. アラビア語のテキストは???として保存されます