Można to zrobić bez użycia kursora i pętli, do zapytania potrzebujemy oznaczenia czy dany rekord ma w dacie od datę początkową, czy datę końcową, czy obie, później pozostajeproste zapytanie o te wartości.
Krokowo
-
widok cteS pobiera dane z tabeli i pobiera poprzednie daty od/do (p_od,p_do) oraz następne daty od/do (n_do,n_od)
n_od | n_do | p_od | p_do | Artykul | data_od | data_do | data_odInt | data_doInt
---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ----------------
2009-10-26 | 2009-11-21 | NULL | NULL | 1 | 2009-03-20 | 2009-04-05 | 39890 | 39906
2009-11-16 | 2010-04-11 | 2009-03-20 | 2009-04-05 | 1 | 2009-10-26 | 2009-11-21 | 40110 | 40136
2009-12-23 | 2010-01-11 | 2009-10-26 | 2009-11-21 | 1 | 2009-11-16 | 2010-04-11 | 40131 | 40277
2010-01-11 | 2010-04-14 | 2009-11-16 | 2010-04-11 | 1 | 2009-12-23 | 2010-01-11 | 40168 | 40187
2011-03-17 | 2011-07-14 | 2009-12-23 | 2010-01-11 | 1 | 2010-01-11 | 2010-04-14 | 40187 | 40280
2011-06-12 | 2011-08-14 | 2010-01-11 | 2010-04-14 | 1 | 2011-03-17 | 2011-07-14 | 40617 | 40736
2011-08-15 | 2011-08-21 | 2011-03-17 | 2011-07-14 | 1 | 2011-06-12 | 2011-08-14 | 40704 | 40767
NULL | NULL | 2011-06-12 | 2011-08-14 | 1 | 2011-08-15 | 2011-08-21 | 40768 | 40774
-
widok o korzysta z cteS i oznacza czy coś jest końcem okresu (kolumna k) jak i początkiem (p)
Początek jest wtedy jeśli jest to pierwszy i data_od nie wchodzi w zakres poprzedniego okresu,
koniec jest wtedy jesli jest to ostani rekord lub data_do jest mniejsza od następnej daty_od
n_od |
n_do |
p_od |
p_do |
Artykul |
data_od |
data_do |
data_odInt |
data_doInt |
p |
k |
2009-10-26 |
2009-11-21 |
NULL |
NULL |
1 |
2009-03-20 |
2009-04-05 |
39890 |
39906 |
1 |
1 |
2009-11-16 |
2010-04-11 |
2009-03-20 |
2009-04-05 |
1 |
2009-10-26 |
2009-11-21 |
40110 |
40136 |
1 |
0 |
2009-12-23 |
2010-01-11 |
2009-10-26 |
2009-11-21 |
1 |
2009-11-16 |
2010-04-11 |
40131 |
40277 |
0 |
0 |
2010-01-11 |
2010-04-14 |
2009-11-16 |
2010-04-11 |
1 |
2009-12-23 |
2010-01-11 |
40168 |
40187 |
0 |
0 |
2011-03-17 |
2011-07-14 |
2009-12-23 |
2010-01-11 |
1 |
2010-01-11 |
2010-04-14 |
40187 |
40280 |
0 |
1 |
2011-06-12 |
2011-08-14 |
2010-01-11 |
2010-04-14 |
1 |
2011-03-17 |
2011-07-14 |
40617 |
40736 |
1 |
0 |
2011-08-15 |
2011-08-21 |
2011-03-17 |
2011-07-14 |
1 |
2011-06-12 |
2011-08-14 |
40704 |
40767 |
0 |
0 |
NULL |
NULL |
2011-06-12 |
2011-08-14 |
1 |
2011-08-15 |
2011-08-21 |
40768 |
40774 |
0 |
1 |
- wynik to pobranie rekordów z o gdzie jest znacznik początku i końca i podmiana dat.
Skrypt do testów:
--DANE TESTOWE
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[source](
[Artykul] [int] NULL,
[data_od] [date] NULL,
[data_do] [date] NULL,
[data_odInt] [float] NULL,
[data_doInt] [float] NULL
) ON [PRIMARY]
GO
INSERT INTO [dbo].[source] ([Artykul], [data_od], [data_do], [data_odInt], [data_doInt])
VALUES (1, '20090320', '20090405', 39890, 39906)
,(1, '20091026', '20091121', 40110, 40136)
,(1, '20091116', '20100411', 40131, 40277)
,(1, '20091223', '20100111', 40168, 40187)
,(1, '20100111', '20100414', 40187, 40280)
,(1, '20110317', '20110714', 40617, 40736)
,(1, '20110612', '20110814', 40704, 40767)
,(1, '20110815', '20110821', 40768, 40774)
,(2, '20110609', '20110714', 40701, 40736)
,(2, '20110612', '20110814', 40704, 40767)
,(2, '20110815', '20110821', 40768, 40774)
,(2, '20130126', '20130207', 41298, 41310)
,(2, '20130802', '20130803', 41486, 41487)
,(2, '20140225', '20140316', 41693, 41712)
,(2, '20140317', '20140330', 41713, 41726)
,(2, '20141201', '20141204', 41972, 41975)
,(2, '20141226', '20141229', 41997, 42000)
,(2, '20141228', '20141230', 41999, 42001)
,(2, '20150109', '20150113', 42011, 42015)
,(2, '20150531', '20150531', 42153, 42153)
,(2, '20151104', '20151106', 42310, 42312)
,(2, '20170101', '99990909', 42734, 2958350)
,(3, '20110609', '20110714', 40701, 40736)
,(3, '20110612', '20110814', 40704, 40767)
,(3, '20110815', '20110821', 40768, 40774)
,(3, '20160620', '20160809', 42539, 42589)
,(3, '20160620', '20160624', 42539, 42543)
,(3, '20161109', '99990909', 42681, 2958350)
Zapytanie:
with cteS as (
select
lead(data_od,1) over (partition by artykul order by data_od) n_od,
lead(data_do,1) over (partition by artykul order by data_od) n_do,
lag(data_od,1) over (partition by artykul order by data_od) p_od,
lag(data_do,1) over (partition by artykul order by data_od) p_do,
*
from
dbo.source s)
, o as (
select
*
,case
when p_od is null then 1
else
case when dateadd(d,-1,data_od) between p_od and p_do then 0
else 1
end
end p
,case
when n_do is null then 1
else
case
when dateadd(d,1,data_do) < n_od then 1
else 0
end
end k
from
ctes)
select distinct
artykul
,case
when p=1 then data_od
else
lag(data_od,1) over (partition by artykul order by data_od)
end data_od
,case
when k=1 then data_do
else
lead(data_do,1) over (partition by artykul order by data_od)
end data_do
from
o
where
p+k>=1
Wynik:
artykul |
data_od |
data_do |
1 |
2009-03-20 |
2009-04-05 |
1 |
2009-10-26 |
2010-04-14 |
1 |
2011-03-17 |
2011-08-21 |