从某个日期范围内的价目表更新未结订单

McN*_*ets 7 sql-server-2005 sql-server

设置

我已经在reextesterdbfiddle上设置了一个示例。

设想

Price list : 它是产品价格表,一个产品可以有多个活动价格,甚至是未来价格。

+---------+-------+------------+--------+--------+
| product | price | date_price |  base  | active |
+---------+-------+------------+--------+--------+
|   0125  |    90 | 01.01.2017 |  1200  |    0   |
|   0125  |   100 | 25.01.2017 |  1000  |    1   |
|   0125  |   110 | 27.02.2017 |   500  |    1   |
+---------+-------+------------+--------+--------+
|   1200  |   140 | 01.01.2017 |  2000  |    0   |
|   1200  |   150 | 01.02.2017 |  1500  |    1   |
|   1200  |   160 | 27.02.2017 |  1000  |    1   |
+---------+-------+------------+--------+--------+
Run Code Online (Sandbox Code Playgroud)

订单挂单有价格和订单日期

+---------+------------+-------+--------+
| product | order_date | price |  base  |
+---------+------------+-------+--------+
|   0125  | 19.02.2017 |  100  |  1000  |
|   0125  | 20.02.2017 |  100  |  1000  |
|   0125  | 21.02.2017 |  100  |  1000  |
|   0125  | 22.02.2017 |  100  |  1000  |
|   0125  | 23.02.2017 |  100  |  1000  |
|   0125  | 28.02.2017 |  110  |   500  |
+---------+------------+-------+--------+
|   1200  | 19.02.2017 |  150  |  1500  |
|   1200  | 20.02.2017 |  150  |  1500  |
|   1200  | 21.02.2017 |  150  |  1500  |
|   1200  | 22.02.2017 |  150  |  1500  |
|   1200  | 23.02.2017 |  150  |  1500  |
|   1200  | 28.02.2017 |  160  |  1000  |
+---------+------------+-------+--------+
Run Code Online (Sandbox Code Playgroud)

每次我们在列表中添加新价格时,我们都必须更新受影响的挂单行。

例如,如果我们添加:

+---------+-------+------------+--------+--------+
| product | price | date_price |  base  | active |
+---------+-------+------------+--------+--------+
|   0125  |   105 | 21.02.2017 |  1300  |    1   |
|   1200  |   155 | 21.02.2017 |  1400  |    1   |
+---------+-------+------------+--------+--------+
Run Code Online (Sandbox Code Playgroud)

新的价目表必须是:

+---------+------------+-------+--------+
| product | order_date | price |  base  |
+---------+------------+-------+--------+
|   0125  | 19.02.2017 |  100  |  1000  |
|   0125  | 20.02.2017 |  100  |  1000  |
|   0125  | 21.02.2017 |  105  |  1300  | *
|   0125  | 22.02.2017 |  105  |  1300  | * Affected rows
|   0125  | 23.02.2017 |  105  |  1300  | *
|   0125  | 28.02.2017 |  110  |   500  | 
+---------+------------+-------+--------+
|   1200  | 19.02.2017 |  150  |  1500  |
|   1200  | 20.02.2017 |  150  |  1500  |
|   1200  | 21.02.2017 |  150  |  1500  | *
|   1200  | 22.02.2017 |  150  |  1500  | * Affectd rows between 21.02.2017 and 27.02.2017
|   1200  | 23.02.2017 |  150  |  1500  | *
|   1200  | 28.02.2017 |  160  |  1000  |
+---------+------------+-------+--------+
Run Code Online (Sandbox Code Playgroud)

我想使用单个查询更新受影响的记录。

由于有另一个价格从 27.02.2017 开始,28.02.2017 的订单不受插入价格的影响。

实际过程

现在,我使用一个子查询来搜索价格列表表中匹配的第一个日期,但现在我也需要更新base字段。(还有两个或三个以上的字段),我想避免使用两个或更多子查询。

update @orders
set    price = (select   top 1 pl.price
                from     @price_list pl
                where    pl.product = o.product
                and      pl.date_price <= o.order_date
                and      active = 1
                order by pl.date_price desc),
       base  = (select   top 1 pl.base
                from     @price_list pl
                where    pl.product = o.product
                and      pl.date_price <= o.order_date
                and      active = 1
                order by pl.date_price desc)
from   @orders o
where  o.product in ('0125', '1200');  --<<< select distinct product from inserted
Run Code Online (Sandbox Code Playgroud)

请随时更正我的文字,我知道我的英语语法不够好。

Sco*_*red 5

我在以下使用CROSS APPLY 的解决方案中使用了你的 dbfiddler 代码

declare @price_list table(product varchar(20), price int, date_price datetime, base int, active tinyint);
insert into @price_list values
('0125',  90, '2017-01-01', 1200, 0), 
('0125', 100, '2017-01-25', 1000, 1), 
('0125', 110, '2017-02-27', 500,  1),
('1200', 140, '2017-01-01', 2000, 0), 
('1200', 150, '2017-02-01', 1500, 1), 
('1200', 160, '2017-02-27', 1000, 1);

declare @orders table(product varchar(20), order_date datetime, price int, base int);
insert into @orders values
('0125', '2017-02-19', 100, 1000), 
('0125', '2017-02-20', 100, 1000),
('0125', '2017-02-21', 100, 1000), 
('0125', '2017-02-22', 100, 1000),
('0125', '2017-02-23', 100, 1000), 
('0125', '2017-02-28', 110,  500),
('1200', '2017-02-19', 150, 1500), 
('1200', '2017-02-20', 150, 1500),
('1200', '2017-02-21', 150, 1500), 
('1200', '2017-02-22', 150, 1500),
('1200', '2017-02-23', 150, 1500), 
('1200', '2017-02-28', 160, 1000);



declare @new_date_price datetime = '2017-02-21';


-- add a new price to the list
--
insert into @price_list values ('0125', 105, @new_date_price - 1, 1300, 1);
insert into @price_list values ('1200', 155, @new_date_price - 1, 1400, 1);


-- update orders price and base, according products price list date price
--
-- I'd like to avoid use 2 (or more) subqueries
--
UPDATE o
SET o.Price = ca.price
    ,o.base = ca.base
FROM @Orders o
CROSS APPLY (
    SELECT TOP 1 pl.price AS price
        ,pl.base AS base
    FROM @Price_List pl
    WHERE pl.product = o.product
        AND pl.date_price <= o.order_date
        AND active = 1
    ORDER BY pl.date_price DESC
    ) ca
WHERE o.product IN (
        '0125'
        ,'1200'
        );--<<< select distinct product from inserted
-- final result
--
select * from @price_list order by product, date_price;
select * from @orders order by product, order_date;
Run Code Online (Sandbox Code Playgroud)