2017-06-09 126 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