4

SQLServer 2008 で、理解できない奇妙な動作に遭遇しました。ユニークな顧客とユニークな支払いをすばやく組み合わせたいと思っていました。

このクエリを使用すると、期待どおりの結果が得られます。各 CustomerId は、異なる PaymentId とペアになっています。

SELECT CustomerId, PaymentId, RowNumber1, RowNumber2
FROM (
    SELECT
        c.Id as CustomerId,
        p.Id as PaymentId,
        ROW_NUMBER() OVER (PARTITION BY p.Id ORDER BY p.Id) AS RowNumber1,
        ROW_NUMBER() OVER (PARTITION BY c.Id ORDER BY c.Id) AS RowNumber2
    FROM Customer as c
    CROSS JOIN Payment as p
) AS INNERSELECT WHERE RowNumber2 = 1

+------------+-----------+------------+------------+
| CustomerId | PaymentId | RowNumber1 | RowNumber2 |
+------------+-----------+------------+------------+
|          4 |         1 |          1 |          1 |
|          5 |         2 |          2 |          1 |
+------------+-----------+------------+------------+

ただし、外側の選択から RowNumber1 列を削除すると、結果が変わるようです。内部の select ステートメントには触れていませんが、PaymentId のすべての値が 1 になりました。

SELECT CustomerId, PaymentId, RowNumber2
FROM (
    SELECT
        c.Id as CustomerId,
        p.Id as PaymentId,
        ROW_NUMBER() OVER (PARTITION BY p.Id ORDER BY p.Id) AS RowNumber1,
        ROW_NUMBER() OVER (PARTITION BY c.Id ORDER BY c.Id) AS RowNumber2
    FROM Customer as c
    CROSS JOIN Payment as p
) AS INNERSELECT WHERE RowNumber2 = 1

+------------+-----------+------------+
| CustomerId | PaymentId | RowNumber2 |
+------------+-----------+------------+
|          4 |         1 |          1 |
|          5 |         1 |          1 |
+------------+-----------+------------+

外部選択から列を削除すると PaymentId 列の値が変更される理由を誰かに説明してもらえますか? 結果セットの行番号を必要とせずに、目的の目標を達成するために他にどのような方法を使用できますか?

4

1 に答える 1

5

これは、サブクエリ内の row_number() の順序が通常定義されていないためです。交差結合を行うと、行は任意の順序になる可能性があります

かもしれない:

CUSTOMERID PAYMENTID
         4         1    
         4         2    
         5         2    
         5         1

またはそれは可能性があります

CUSTOMERID PAYMENTID
         4         1    
         4         2    
         5         1    
         5         2

CUSTOMERID によって最初のレコードセット パーティションの row_number を計算すると、次のようになります。

CUSTOMERID PAYMENTID ROWNUMBER
         4         1         1  
         4         2         2
         5         2         1
         5         1         2

CUSTOMERID によって 2 番目のレコードセット パーティションの row_number を計算すると、次のようになります。

CUSTOMERID PAYMENTID ROWNUMBER
         4         1         1  
         4         2         2
         5         1         1
         5         2         2

ランダムな顧客と支払いをペアにしたい場合は、これを行うことができます

with cte_cust as (
    select id, row_number() over (order by id) as row_num
    from Customer
), cte_pay as (
    select id, row_number() over (order by id) as row_num
    from Payment
)
select
    c.id as CustomerId,
    p.id as PaymentId
from cte_cust as c
    inner join cte_pay as p on p.row_num = c.row_num

支払いよりも多くの顧客がいる場合、一部の顧客は結果に表示されないことに注意してください (逆も同様です)。

sql fiddle demo

于 2013-08-21T19:25:55.000 に答える