sco*_*192 4 sql t-sql sql-server
我在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 |
+------------+-----------+------------+------------+
Run Code Online (Sandbox Code Playgroud)
但是,如果我从外部选择中删除RowNumber1列,结果似乎会改变。现在,即使我没有触摸内部选择语句,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 |
+------------+-----------+------------+
Run Code Online (Sandbox Code Playgroud)
谁能向我解释为什么从外部选择中删除一列会导致PaymentId列中的值发生变化?在不需要结果集中的行号的情况下,我还可以使用什么其他方法来实现期望的目标?
这是因为通常未定义子查询中row_number()的顺序。进行交叉连接时,行可以按任何顺序排列
它可能是:
CUSTOMERID PAYMENTID
4 1
4 2
5 2
5 1
Run Code Online (Sandbox Code Playgroud)
或者可能是
CUSTOMERID PAYMENTID
4 1
4 2
5 1
5 2
Run Code Online (Sandbox Code Playgroud)
当您通过CUSTOMERID计算第一个记录集分区中的row_number时,会得到
CUSTOMERID PAYMENTID ROWNUMBER
4 1 1
4 2 2
5 2 1
5 1 2
Run Code Online (Sandbox Code Playgroud)
当您通过CUSTOMERID计算第二个记录集分区中的row_number时,您将获得
CUSTOMERID PAYMENTID ROWNUMBER
4 1 1
4 2 2
5 1 1
5 2 2
Run Code Online (Sandbox Code Playgroud)
如果您只将随机客户和付款配对,则可以执行此操作
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
Run Code Online (Sandbox Code Playgroud)
请注意,如果您的客户多于付款,则某些客户将不会出现在结果中(反之亦然)。