如何根据OrderItem记录值

时间:2016-06-29 16:50:00

标签: sql sql-server tsql

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

场景1:连接到订单的所有3个OrderItem都是“已取消” - 不更新订单标记

场景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返回多条记录。不确定这是不是一个问题。

3 个答案:

答案 0 :(得分:1)

这样的事情:

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

答案 1 :(得分: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)如果你需要更新到差异,请使用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')
)

答案 2 :(得分:0)

看起来您需要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