【问题标题】:Update a table by joining to the most recent record of another table that meets some condition通过加入满足某些条件的另一个表的最新记录来更新表
【发布时间】:2018-04-20 23:34:35
【问题描述】:

我试图避免在此解决方案中使用循环,而是使用基于集合的操作。

我需要根据最近一次与另一个表的连接来更新表中的每条记录。我的第一个想法是加入我需要“最近日期”的表并根据加入条件分组,但使用 GROUP BYUPDATE 是无效的。

这是我目前所拥有的。我觉得这将通过 CTE 解决...

CREATE TABLE Part (
    Area            VARCHAR(10) NOT NULL,
    SequenceNumber  INT         NOT NULL,
    DateAdded       DATETIME    NOT NULL
);
INSERT INTO Part VALUES
('A', 1, '2018-04-01'),
('A', 1, '2018-04-02'),
('A', 2, '2018-04-03'),
('A', 2, '2018-04-04'),
('B', 2, '2018-04-04'),
('B', 2, '2018-04-03'),
('B', 3, '2018-04-02'),
('B', 3, '2018-04-01');

DECLARE @Filters    TABLE
(
    Area            VARCHAR(10),
    StartingSeqNum  INT,
    StartTime       DATETIME 
);
INSERT INTO @Filters VALUES
('A', 2, NULL),
('B', 3, NULL);

-- Update each StartTime in @Filters with the most recent
-- DateAdded of the corresponding SequenceNumber in the Part table per Area.
UPDATE f
SET f.StartTime = MAX(p.DateAdded)
FROM
    @Filters f
    INNER JOIN Part p ON p.Area = f.Area
        AND p.SequenceNumber = f.StartingSeqNum
GROUP BY
    p.Area,
    p.SequenceNumber;

根据上面的示例数据,该操作应在@Filters 中填充以下值:

('A', 2, '2018-04-04')
('B', 3, '2018-04-02')

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    可以使用 CTE 来执行此操作,如下所示:

    ;with maxParts as
    (
        select Area, SequenceNumber, MAX(dateadded) as maxDateAdded 
        from Part
        group by Area, SequenceNumber
    )
    UPDATE f
    SET f.StartTime = p.maxDateAdded
    from @Filters f
        inner join maxParts p 
            on f.Area = p.Area
            and f.StartingSeqNum = p.SequenceNumber
    

    但是,您也可以将 CTE 重写为子查询:

    UPDATE f
    SET f.StartTime = p.maxDateAdded
    from @Filters f
        inner join (
                select Area, SequenceNumber, MAX(dateadded) as maxDateAdded 
                from Part
                group by Area, SequenceNumber
            ) p 
            on f.Area = p.Area
            and f.StartingSeqNum = p.SequenceNumber
    

    这些查询计划应该是相同的 - 所有 CTE 真正允许您的是看起来更清晰的查询以及轻松重用该 SELECT 的能力。

    【讨论】:

    • 感谢您的帮助!
    • 没问题!未来基于集合的工作需要考虑的事项 - 如果您可以使用 select 语句生成结果集以获得您想要的结果,那么在子查询或 CTE 中使用这些 selects 通常很容易。跨度>
    【解决方案2】:

    (a)

    UPDATE Filters
           SET Filters.StartTime = (SELECT max(Part.DateAdded)
                                    FROM Part
                                    WHERE Part.Area = Filters.Area
                                          AND Part.SequenceNumber = Filters.StartingSeqNum)
           FROM @Filters Filters;
    

    (b)

    UPDATE Filters
           SET Filters.StartTime = X.StartTime
           FROM @Filters Filters
                INNER JOIN (SELECT max(Part.DateAdded) StartTime,
                                   Part.Area,
                                   Part.SequenceNumber
                                   FROM Part
                                   GROUP BY Part.Area,
                                            Part.SequenceNumber) X
                           ON X.Area = Filters.Area
                              AND X.SequenceNumber = Filters.StartingSeqNum;
    

    (a)和(b)都应该做你想做的事。我不确定哪个更好。也许(b)可以重用子查询关系,因此总体成本更低。

    【讨论】:

    • 感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2013-11-26
    • 2012-10-18
    • 1970-01-01
    • 2018-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-23
    相关资源
    最近更新 更多