根据另一个表中的有序数据更新表

时间:2019-01-24 15:32:11

标签: sql sql-server

我们的数据库是SQL Server2014。我将简化示例以解释我的问题。

TableA具有列:

CustomerID (primary key), LatestOrderedItem, LatestOrderDate

TableB具有列:

OrderID, CustomerID, OrderedItem, PurchaseDate

我想用LatestOrderedItem(基于购买日期)的客户的最新/最近订单更新LatestOrderDate的{​​{1}}和TableA

对此最好/最有效的更新说明是什么? (实际上,在我们的情况下,两个表都有数百万条记录。)

我尝试过的方法,但是仍然很慢:

方法1:

TableB

方法2:

UPDATE a
SET LatestOrderedItem = (SELECT TOP 1
                                OrderedItem
                         FROM TableB
                         WHERE CustomerID = a.CustomerID
                         ORDER BY PurchaseDate DESC),
    LatestOrderDate = (SELECT TOP 1
                              PurchaseDate
                       FROM TableB
                       WHERE CustomerID = a.CustomerID
                       ORDER BY PurchaseDate DESC)
FROM TableA a;

3 个答案:

答案 0 :(得分:0)

尝试使用CROSS APPLYTOP

UPDATE a SET 
    LatestOrderedItem = c.OrderedItem,
    LatestOrderDate = c.PurchaseDate
FROM 
    TableA a
    CROSS APPLY (
        SELECT TOP 1
            b.OrderedItem,
            b.PurchaseDate
        FROM
            TableB b
        WHERE
            a.CustomerID = b.CustomerID
        ORDER BY
            b.PurchaseDate DESC
    ) AS C

以下索引是此更新性能的关键。可以选择include OrderedItem列,或创建索引clustered,尽管这样做有副作用。

CREATE NONCLUSTERED INDEX NCI_TableB_CustomerID_PurchaseDate ON TableB (CustomerID, PurchaseDate) -- INCLUDE (OrderedItem)

PD :请阅读Larnu的评论,因为将这些数据存储在表中暗示着反规范化,并且从长远来看会带来麻烦。

答案 1 :(得分:0)

另一个选项是派生表中的窗口函数。

update a
    set a.LatestOrderedItem = b.OrderedItem
        ,a.LatestOrderDate = b.PurchaseDate
from TableA a
inner join
    (select CustomerID, OrderedItem, PurchaseDate, 
        row_number() over (partition by CustomerID order by PurchaseDate desc) as seq 
        from TableB) on b.CustomerID = a.CustomerID and b.seq = 1

答案 2 :(得分:0)

窗口功能,一次扫描要更新的两列:

UPDATE a
SET a.LatestOrderedItem = b.OrderedItem,
    a.LatestOrderDate = b.PurchaseDate
FROM TableA a
    JOIN
    (
        SELECT CustomerID,
               OrderedItem,
               PurchaseDate,
               ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY PurchaseDate DESC) RN
        FROM TableB
        WHERE CustomerID = a.CustomerID
    ) b
        ON a.CustomerID = b.CustomerID
           AND b.RN = 1;