根据另一个表中的两列和多行有条件地更新表

时间:2016-08-31 13:45:01

标签: sql-server sql-update

我需要使用基于表2的正确条目更新表1中的外键。正确的外键是最早的日期,但不是在表2中的下一个生效日期之前。如果有多个条目在表2中具有相同的生效日期,然后使用修改日期列作为平局破坏者并选择最近的一个。这是基于表的结构(所有日期都是日期格式):

Table 1
pK1   PeriodStartDate               pK2    
1     2016-04-01 00:00:00.000               
2     2016-07-01 00:00:00.000

Table 2
pK2    EffectiveFrom                ModifiedDate
3      2016-03-01 00:00:00.000      2016-04-01 00:00:00.000
4      2016-05-01 00:00:00.000      2016-06-01 00:00:00.000
5      2016-05-01 00:00:00.000      2016-06-02 00:00:00.000

所以在上面的例子中,表1看起来像这样:

pK1   PeriodStartDate                  pK2    
1     2016-04-01 00:00:00.000          3     
2     2016-07-01 00:00:00.000          5

这是因为第1行是在3月1日到5月1日之间(从表2开始)。对于第2行,它是在最后一个日期之后,但由于有两个相似的开始日期,我们选择最后修改日期。

我不确定解决方案。我正在尝试这样的事情:

UPDATE table1 
SET pK2 = table2.pK2
FROM table2 
WHERE PeriodStartDate > (SELECT FIRST(table2.EffectiveFrom) FROM table2)

我只是不确定如何找到一个受另一行限制的条目(然后需要另一列用于分配器)

1 个答案:

答案 0 :(得分:1)

首先,您需要在row_number()上应用Table2,在PeriodStart上进行分区,并按ModifiedDate(desc)排序。请致电MaxModified; 1始终是最近修改过的记录。

pK2 PeriodStart             ModifiedDate            MaxModified
3   2016-03-01 00:00:00.000 2016-04-01 00:00:00.000 1
5   2016-05-01 00:00:00.000 2016-06-02 00:00:00.000 1
4   2016-05-01 00:00:00.000 2016-06-01 00:00:00.000 2

然后,仅在MaxModified=1的位置添加一个新的“id”,这样我们就可以排队一个开始日期,下一行开始日期(我们的结束日期)。这也是使用row_number()订购的PeriodStart函数完成的。

pK2 PeriodStart             ModifiedDate            MaxModified myID
3   2016-03-01 00:00:00.000 2016-04-01 00:00:00.000 1           1
5   2016-05-01 00:00:00.000 2016-06-02 00:00:00.000 1           2

然后我们获取该结果并将其连接到自己偏移一行以获得每个原始行的结束日期值。

pK2 PeriodStart             ModifiedDate             MaxModified    myID    PeriodEnd
3   2016-03-01 00:00:00.000 2016-04-01 00:00:00.000  1              1       2016-05-01 00:00:00.000
5   2016-05-01 00:00:00.000 2016-06-02 00:00:00.000  1              2       NULL

一旦我们拥有了这个,就可以简单地加入开始/结束日期以获得pk2值。

完整的脚本......

DECLARE @Table1 TABLE (pK1 INT, PeriodStart DATETIME, pK2 INT)
DECLARE @Table2 TABLE (pK2 INT, PeriodStart DATETIME, ModifiedDate DATETIME)

INSERT INTO @Table1
VALUES (1,'2016-04-01',NULL),
       (2,'2016-07-01',NULL)

INSERT INTO @Table2
VALUES (3,'2016-03-01','2016-04-01'),
       (4,'2016-05-01','2016-06-01'),
       (5,'2016-05-01','2016-06-02')

;WITH OrderedList AS
(
    SELECT *, 
           ROW_NUMBER() OVER(PARTITION BY PeriodStart ORDER BY ModifiedDate DESC) AS MaxModified
    FROM @Table2
),X AS
    (
        SELECT *,
               ROW_NUMBER() OVER(ORDER BY PeriodStart) AS myID
        FROM OrderedList
        WHERE MaxModified=1
    ), Y AS
        (
            SELECT L.*, R.PeriodStart AS PeriodEnd
            FROM X L
            LEFT JOIN X R ON L.myID=R.myID-1 AND R.MaxModified=1
            WHERE L.MaxModified=1
        )

UPDATE T SET pK2=Y.pK2
FROM @Table1 T
LEFT JOIN Y ON T.PeriodStart >= Y.PeriodStart AND T.PeriodStart < COALESCE(Y.PeriodEnd,CURRENT_TIMESTAMP)

SELECT *
FROM @Table1