根据多个列的条件连接两个表

Join two tables with conditions depending on multiples columns

在 SQL Server 2008 中,我想加入两个 table 可能有重复的键,但与其他列的信息匹配是唯一的。

对于简化的购买记录示例,

Table A:
UserId  PayDate Amount
1       2015    100
1       2010    200
2       2014    150

Table B:
UserId  OrderDate Count
1       2009      4
1       2014      2
2       2013      5

Desired Result:
UserId  OrderDate PayDate Amount Count
1       2009      2010    200    4
1       2014      2015    100    2
2       2013      2014    150    5

保证:

  1. Table A 和 Table B 的行数相同,并且 table 中的 UserId 是同一组数字。

  2. 对于任何 UserIdPayDate 总是晚于 OrderDate

  3. 具有相同 UserId 的行按 Date 的排序序列匹配。例如,Table A 中的第 1 行应匹配 Table B

  4. 中的第 2 行

我的想法是,在两个 table 上,首先按 Date 排序,然后添加另一个 Id 列,然后加入此 Id 列。但我无权向数据库中写入任何内容。我该如何完成这个任务?

Row_Number() 将成为您的朋友。它允许您向结果集添加虚拟排序。

运行 并研究输出:

SELECT UserID
     , OrderDate
     , "Count" As do_not_use_reserved_words_for_column_names
     , Row_Number() OVER (PARTITION BY UserID ORDER BY OrderDate) As sequence
FROM   table_b

PARTITION BY 确定计数器何时应为 "reset" 即它应在更改 UserID

后重新启动

ORDER BY,嗯,你猜对了——决定了序列的顺序!

把这一切放在一起:

; WITH payments AS (
  SELECT UserID
       , PayDate
       , Amount
       , Row_Number() OVER (PARTITION BY UserID ORDER BY PayDate) As sequence
  FROM   table_b
)
, orders AS (
  SELECT UserID
       , OrderDate
       , "Count" As do_not_use_reserved_words_for_column_names
       , Row_Number() OVER (PARTITION BY UserID ORDER BY OrderDate) As sequence
  FROM   table_b
)
SELECT orders.UserID
     , orders.OrderDate
     , orders.do_not_use_reserved_words_for_column_names
     , payments.PayDate
     , payments.Amount
FROM   orders
 LEFT
  JOIN payments
    ON payments.UserID   = orders.UserID
   AND payments.sequence = orders.sequence

P.S。我选择了外部连接,因为我认为不会总是为每个订单付款。

尝试:

;WITH t1
AS
(
    SELECT UserId, PayDate, Amount, 
           ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY PayDate) AS RN
    FROM TableA
),
t2
AS
(
    SELECT UserId,  OrderDate, [Count],
           ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY OrderDate) AS RN
    FROM TableB
)
SELECT t1.UserId,  t2.OrderDate, t1.PayDate,  t1.Amount,  t2.[Count]
FROM t1
INNER JOIN t2
   ON t1.UserId = t2.UserId AND t1.RN = t2.RN