我有一个SQL查询问题。我在SQL Server 2014中有下表。
declare @t table (STORE_ID int, INDEX_ID int, START_DATE datetime,
END_DATE datetime,
GROSS_SALES_PRICE decimal(10,2),
NET_SALES_PRICE INT
);
insert into @t
values (3,22,'2014-08-01 00:00:00.000', '2014-09-30 23:59:59.000', 29.99,25),
(3,22,'2014-10-01 00:00:00.000', '2014-12-31 23:59:59.000', NULL,NULL),
(3,22,'2015-01-01 00:00:00.000', '2015-09-30 23:59:59.000', 39.99,28),
(4,22,'2016-01-01 00:00:00.000', '2016-07-31 23:59:59.000', 29.99,25),
(4,22,'2016-08-01 00:00:00.000', '2016-12-31 23:59:59.000', NULL,NULL),
(4,22,'2017-01-01 00:00:00.000', '2018-09-30 23:59:59.000', 39.99,28),
(1,22,'2014-08-30 00:00:00.000', '2014-10-31 23:59:59.000', 39.99,28),
(1,22,'2014-11-01 00:00:00.000', '2016-09-30 23:59:59.000', 20.99,15)
正如您所看到的,某些行中的GROSS_SALES_PRICE
和NET_SALES_PRICE
中有一些NULLS。这种情况是从STORE_ID
等于1的行中获取此价格。例如,如果您在第二行中有NULL值,则可以从商店编号1中获取此价格的价格。但是在此类型中您有2种不同的价格。因此,您必须将该NULL行拆分为两行,并采用两种不同的价格。如果peroid没有加工部分,则行的一部分应保留为NULL。所有日期都是可分的。结果应该是这样的。
declare @t2 table (STORE_ID int, INDEX_ID int, START_DATE datetime,
END_DATE datetime,
GROSS_SALES_PRICE decimal(10,2),
NET_SALES_PRICE INT
);
insert into @t2
values (3,22,'2014-08-01 00:00:00.000', '2014-09-30 23:59:59.000', 29.99,25),
(3,22,'2014-10-01 00:00:00.000', '2014-10-31 23:59:59.000', 39.99,28),
(3,22,'2014-11-01 00:00:00.000', '2014-12-31 23:59:59.000', 20.99,15),
(3,22,'2015-01-01 00:00:00.000', '2015-09-30 23:59:59.000', 39.99,28),
(4,22,'2016-01-01 00:00:00.000', '2016-07-31 23:59:59.000', 29.99,25),
(4,22,'2016-08-01 00:00:00.000', '2016-09-30 23:59:59.000', 20.99,15),
(4,22,'2016-10-01 00:00:00.000', '2016-12-31 23:59:59.000', NULL,NULL),
(4,22,'2017-01-01 00:00:00.000', '2018-09-30 23:59:59.000', 39.99,28),
(1,22,'2014-08-30 00:00:00.000', '2014-10-31 23:59:59.000', 39.99,28),
(1,22,'2014-11-01 00:00:00.000', '2016-09-30 23:59:59.000', 20.99,15)
答案 0 :(得分:1)
日历/日期表可以简化此操作,但我们也可以使用查询使用common table expression生成临时日期表。
加入来自index_id
的每个store_id 1
的价格加上日期表,我们可以加入并汇总以获取缺失值的价格。然后使用union all
返回价格行,以及我们尝试填写价格的行:
/* -- dates --*/
declare @fromdate datetime, @thrudate datetime;
select @fromdate = min(start_date), @thrudate = max(end_date) from @t;
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
select top (datediff(day, @fromdate, @thrudate)+1)
[Date]=convert(datetime,dateadd(day,row_number() over(order by (select 1))-1,@fromdate))
, [End_Date]=convert(datetime,dateadd(second,-1,dateadd(day,row_number() over(order by (select 1)),@fromdate)))
from n as deka cross join n as hecto cross join n as kilo
cross join n as tenK cross join n as hundredK
order by [Date]
)
/* -- default price -- */
, cte as (
select
d.index_id
, start_date = d.date
, end_date = d.end_date
, t.gross_sales_price
, t.net_sales_price
from (
select dates.*
, i.index_id
from dates
cross join (select distinct index_id from @t) i
) d
left join (select * from @t where store_id = 1) t
on d.date >= t.start_date
and d.date <= t.end_date
and d.index_id = t.index_id
)
/* -- rows with a price */
select
t.store_id
, t.index_id
, start_date
, end_date
, gross_sales_price
, net_sales_price
from @t t
where t.Gross_Sales_Price is not null
union all
/* -- rows with with a null price */
select
t.store_id
, t.index_id
, start_date = min(d.start_date)
, end_date = max(d.end_date)
, gross_sales_price = d.gross_sales_price
, net_sales_price = d.net_sales_price
from @t t
left join cte d
on t.index_id = d.index_id
and d.start_date >= t.start_date
and d.end_date <= t.end_date
where t.Gross_Sales_Price is null
group by
t.store_id, t.index_id, d.gross_sales_price, d.net_sales_price
order by store_id, index_id
rextester演示:http://rextester.com/QXDNF59094
返回:
+----------+----------+-------------------------+-------------------------+-------------------+-----------------+
| store_id | index_id | start_date | end_date | gross_sales_price | net_sales_price |
+----------+----------+-------------------------+-------------------------+-------------------+-----------------+
| 1 | 22 | 2014-08-30 00:00:00.000 | 2014-10-31 23:59:59.000 | 39.99 | 28 |
| 1 | 22 | 2014-11-01 00:00:00.000 | 2016-09-30 23:59:59.000 | 20.99 | 15 |
| 3 | 22 | 2014-11-01 00:00:00.000 | 2014-12-30 23:59:59.000 | 20.99 | 15 |
| 3 | 22 | 2014-10-01 00:00:00.000 | 2014-10-31 23:59:59.000 | 39.99 | 28 |
| 3 | 22 | 2014-08-01 00:00:00.000 | 2014-09-30 23:59:59.000 | 29.99 | 25 |
| 3 | 22 | 2015-01-01 00:00:00.000 | 2015-09-30 23:59:59.000 | 39.99 | 28 |
| 4 | 22 | 2016-01-01 00:00:00.000 | 2016-07-31 23:59:59.000 | 29.99 | 25 |
| 4 | 22 | 2017-01-01 00:00:00.000 | 2018-09-30 23:59:59.000 | 39.99 | 28 |
| 4 | 22 | 2016-10-01 00:00:00.000 | 2016-12-30 23:59:59.000 | NULL | NULL |
| 4 | 22 | 2016-08-01 00:00:00.000 | 2016-09-30 23:59:59.000 | 20.99 | 15 |
+----------+----------+-------------------------+-------------------------+-------------------+-----------------+
日历和数字表参考: