2013-08-21 65 views
3

我遇到了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 | 
+------------+-----------+------------+------------+ 

但是,如果我從外部select中刪除RowNumber1列,結果似乎會改變。現在PaymentId的每個值都是1,即使我沒有觸及內部select語句。

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 | 
+------------+-----------+------------+ 

任何人都可以向我解釋爲什麼從外部select中刪除列會導致PaymentId列中的值發生更改?我可以使用其他什麼方法來實現我想要的目標,而不需要結果集中的行號?

回答

4

這是因爲您的子查詢中的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 

當你計算第二個row_number記錄分區的CUSTOMERID,你

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

如果你wnat剛剛配對隨機客戶和支付,你可以做到這一點

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

+0

有什麼辦法給它如何傳中後責令其加盟,使我始終得到像我的第一個例子結果的暗示? – scourge192

+0

檢查更新的答案,希望這有助於 –

+0

謝謝,我甚至沒有想過要這樣做 – scourge192