2017-06-09 125 views
1

我有一个SQL查询问题。我下表在SQL服务器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_PRICENET_SALES_PRICE一些空值。这种情况是从STORE_ID等于1的行中获取这个价格。例如,如果您在第二行中有NULL值,您可以从商店编号1的这个周期中获取价格。但是在这个周期中,您有两个不同的价格。所以你必须把这条空行分成两行,并采取两种不同的价格。如果没有加密部分,则行的部分应该保留为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

正如您前面的问题的讨论,日期范围的这种方法是有问题的。另见: [不良习惯踢:错误处理日期/范围查询 - 亚伦伯特兰](http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/16/bad-habits-to-kick- mishandling-date-range-queries.aspx) – SqlZim

回答

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    | 
+----------+----------+-------------------------+-------------------------+-------------------+-----------------+ 

日历和数字表参考:

+0

这是我正在寻找的代码。谢谢:) –

+0

@RafałKobiela乐于帮助! – SqlZim