【问题标题】:How can I update Order records in SQL based on OrderItem record values如何根据 OrderItem 记录值更新 SQL 中的订单记录
【发布时间】:2016-06-29 16:50:00
【问题描述】:

我想更新我的 Orders 表中的标志值,但前提是在我的 OrderItems 表中通过 OrderID 连接到该 Orders 记录的 OrderItems 中至少有一个处于某种状态。

场景 1:连接到订单的所有 3 个 OrderItems 都被“取消” - 不更新订单标志

场景 2:至少有一个与订单相关的 OrderItem 未被“取消” - 更新订单标志

场景 3:连接到订单的所有 OrderItem 均未“取消” - 更新订单标志

如何才能有效地做到这一点?

这是我所拥有的:

UPDATE o
SET   o.Flag = true
FROM Orders o
INNER JOIN OrderItems oi ON oi.OrderID = o.OrderID
WHERE o.Flag = false
AND oi.State <> 'Cancelled'

INNER JOIN 可能会从 OrderItems 返回多条记录。不确定这是否有问题。

【问题讨论】:

  • 一些具有预期结果的示例数据会有所帮助。
  • 我添加了到目前为止的内容。

标签: sql sql-server tsql


【解决方案1】:

基本上,要求的语句应该只为场景 2 和 3 更新 dbo.Orders 表中的行。

1) 如果 - 对于 S2 和 S3 - 您必须使用相同的标志更新订单,则一个解决方案遵循更新:

UPDATE o
SET Flag = 1 -- common flag for S2 and S3
FROM dbo.Orders o
WHEER EXISTS (
    SELECT * FROM dbo.OrderItems oi
    WHERE oi.OrderID = o.OrderID
    -- Uncomment if oi.Status allows NULLs
    AND (/*oi.Status IS NULL OR*/ oi.Status <> 'Cancelled')
)

2) 如果您必须更新到 diff,请使用 Buf。 flags 然后我会使用以下语句

UPDATE o
SET Flag = 
    CASE 
        WHEN EXISTS(SELECT * FROM dbo.OrderItems oi2 WHERE oi2.OrderID = o.OrderID AND oi2.Status = 'Cancelled')
        THEN 2 -- Status for second scenario
        ELSE 3 -- Status for third scenario
    END
FROM dbo.Orders o
WHEER EXISTS (
    SELECT * FROM dbo.OrderItems oi
    WHERE oi.OrderID = o.OrderID
    -- Uncomment if oi.Status allows NULLs
    AND (/*oi.Status IS NULL OR*/ oi.Status <> 'Cancelled')
)

【讨论】:

  • 谢谢。场景 1 正是我所需要的。
【解决方案2】:

类似这样的:

create table orders
(
    orderID int,
    orderName varchar(50),
    orderDate datetime,
    isValidOrderFlag bit
)

create table orderdetail
(
    orderdetailID int,
    orderID int,
    productName varchar(100),
    productCost numeric(9,2),
    quantity int,
    isCancelled bit
)

insert into orders values (1234, 'Bob Garvey', GETDATE() - 5, 0);
insert into orders values (1235, 'Susan  Hamilton', GETDATE() - 5, 0);
insert into orders values (1236, 'Bob Garvey', GETDATE() - 5, 0);
insert into orders values (1237, 'Sarah Smith', GETDATE() - 4, 0);

-- all 3 order items are cancelled do not update orders flag
insert into orderdetail values (10000, 1234, 'thing1', 9.95, 10, 1);
insert into orderdetail values (10001, 1234, 'thing2', 5.99, 10, 1);
insert into orderdetail values (10002, 1234, 'thing3', 1.99, 1, 1);

-- at least one order is cancelled update orders flag
insert into orderdetail values (10000, 1235, 'thing1', 9.95, 10, 1);
insert into orderdetail values (10001, 1235, 'thing2', 5.99, 10, 0);
insert into orderdetail values (10002, 1235, 'thing3', 1.99, 1, 0);

-- at least one order is cancelled update orders flag
insert into orderdetail values (10000, 1236, 'thing1', 9.95, 10, 1);
insert into orderdetail values (10001, 1236, 'thing2', 5.99, 10, 1);
insert into orderdetail values (10002, 1236, 'thing3', 1.99, 1, 0);

-- no orders are cancelled dupdate orders flag
insert into orderdetail values (10000, 1237, 'thing1', 9.95, 10, 0);
insert into orderdetail values (10001, 1237, 'thing2', 5.99, 10, 0);
insert into orderdetail values (10002, 1237, 'thing3', 1.99, 1, 0);

select orderid, max(iscancelled)
from orderdetail
group by orderid

--count detail items
update o
set isvalidorderflag = 1
from 
dbo.orders o
join 
(
    select  orderid
    , count(*) [total_lines]
    , sum(case when iscancelled = 1 then 1 else 0 end) [total]
    from orderdetail
    group by orderid) main on main.orderid = o.orderid
where 
    main.total_lines <> main.total

【讨论】:

    【解决方案3】:

    看起来您需要在 OrderItems 表上使用 DML 触发器,该触发器将更新 Order 状态,与 orderItems 的更改方式无关。
    更新版本

    create trigger tr_OrderItems
       on dbo.OrderItems after insert, update, delete
    as
    begin
       set nocount on
       declare @orders table(orderId int)
       insert @orders(orderid)
       select orderid from inserted
       union --distinct 
       select orderid from deleted
       --update orders
       ;with items as (--calculate counts
          select oi.orderid, count(*) itemCnt,
             count(case status when 'Cancelled' then 1 end) cancelledCnt
             --not 'Cancelled' produce null and not counted
          from dbo.OrderItems oi
               inner join @orders o on o.orderid = oi.orderid 
          group by oi.orderid
       )--CTE
       update orders 
          set flag = case when i.itemCnt = i.cancelledCnt then 'AllCancelled'
                          when i.cancelledCnt = 0 then 'NoneCancelled'
                          else 'SomeCancelled' end
       from orders o
            inner join items i on o.orderid = i.orderid
    end
    

    【讨论】:

    • 这一行` select @orderId=orderId from inserted --insert or u` 是危险的。它假定任何 INSERT 或 UPDATE 操作只会影响一行/OrderID
    • 插入/更新/删除可能会影响OrderItems中的许多行,但它们属于不同Orders的可能性很小。
    猜你喜欢
    • 1970-01-01
    • 2018-07-28
    • 1970-01-01
    • 2019-02-02
    • 1970-01-01
    • 2020-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多