Output data by putting lag in SQL Server - sql

I have one table as below in SQL Server like below.
SELECT * FROM OverlappingDateRanges
Id startDate EndDate
10001 2020-04-01 00:00:00.000 2020-05-25 00:00:00.000
10001 2020-05-26 00:00:00.000 2020-07-15 00:00:00.000
10001 2020-07-17 00:00:00.000 2020-08-15 00:00:00.000
10001 2020-08-16 00:00:00.000 2020-10-15 00:00:00.000
10001 2020-10-16 00:00:00.000 2020-12-31 00:00:00.000
10002 2020-05-01 00:00:00.000 2020-05-29 00:00:00.000
10002 2020-05-30 00:00:00.000 2020-07-08 00:00:00.000
10002 2020-07-09 00:00:00.000 2020-10-01 00:00:00.000
10002 2020-10-03 00:00:00.000 2020-12-31 00:00:00.000
I want output like below where if there is no date difference between end date and next start date of same id, then then date will continue & its should break if end date and next start date is not in continue.
Output should be:
id startDate endDate
10001 2020-04-01 00:00:00.000 2020-07-15 00:00:00.000
10001 2020-07-17 00:00:00.000 2020-12-31 00:00:00.000
10002 2020-05-01 00:00:00.000 2020-10-01 00:00:00.000
10002 2020-10-03 00:00:00.000 2020-12-31 00:00:00.000

This is a type of gaps-and-islands problem. Identify where each output row starts by looking at the previous end. Then do a cumulative sum and aggregate:
select id, min(startdate), max(enddate)
from (select t.*,
sum(case when prev_enddate >= dateadd(day, -1, startdate) then 0 else 1
end) over (partition by id order by startdate) as grp
from (select t.*,
lag(enddate) over (partition by id order by startdate) as prev_enddate
from t
) t
) t
group by id, grp;
Here is a db<>fiddle.

Related

R translation into SQL gap fill

I have a R script that I need to migrate into SQL. In R I can use the tidyr::complete to fill in the gaps no worries. And when I know I can do it in SQL with the cross join function. the problem arises when I want to maintain some of the nulls that exist.
I reduced the results here for simplicity but the sequence would go
if month1 = 2012-01-01 then month2 would sequence every month from 2012-01-01 until today month
if month1 = 2020 then month2 would sequence from 2020-01-01 to 2022-11-01
month1
month2
units
2012-01-01
null
10
2012-01-01
2012-01-01
null
2012-01-01
2012-03-01
15
2012-01-01
2013-01-01
12
2012-01-01
2013-04-01
17
2012-01-01
2013-05-05
5
Ideally I would get
month1
month2
units
2012-01-01
null
10
2012-01-01
2012-01-01
null
2012-01-01
2012-02-01
null
2012-01-01
2012-03-01
15
2012-01-01
2013-01-01
12
2012-01-01
2013-02-01
null
2012-01-01
2013-03-01
null
2012-01-01
2013-04-01
17
2012-01-01
2013-05-05
5
but in SQL I am getting
month1
month2
units
2012-01-01
2012-01-01
null
2012-01-01
2012-02-01
null
2012-01-01
2012-03-01
15
2012-01-01
2013-01-01
12
2012-01-01
2013-02-01
null
2012-01-01
2013-03-01
null
2012-01-01
2013-04-01
17
2012-01-01
2013-05-05
5
SELECT
seq.*
, COALESCE(m.n, 0) AS termed
FROM (
SELECT *
FROM (
SELECT DISTINCT month1
FROM table1
WHERE submit_dt IS NOT NULL
) sign
CROSS JOIN (
SELECT DISTINCT month2
FROM table1
WHERE submit_dt IS NOT NULL
)
WHERE month2 >= mmonth1 and month2 is not null
) seq
LEFT JOIN (
SELECT
t2.month1,
, t2.month2
, COUNT(*) AS units
FROM table2 t2
GROUP BY 1,2
) u ON u.month1 = seq.month1 AND u.month2 = seq.month2
Here is the R version that gives me what I want
df
<- (month1, month2, units) %>%
group_by(month1) %>%
tidyr::complete(month2 = seq.Date(as.Date("2012-01-01"), floor_date(today(), "month"), "month"))
Any help is appreciated. I know it is something super simple I am missing. Thanks
So you want the gaps filled for month year 2012 from 2012-01-01 - currentdate
and the same goes for every year in month1
the foolowing extract first all unique years in the month1 generates all dates from the extract year till now and joins it to the orignal table
CREATE TABLE tab1
("month1" timestamp, "month2" timestamp, "units" varchar(4))
;
INSERT INTO tab1
("month1", "month2", "units")
VALUES
('2012-01-01', NULL, '10'),
('2012-01-01', '2012-01-01', NULL),
('2012-01-01', '2012-03-01', '15'),
('2012-01-01', '2013-01-01', '12'),
('2012-01-01', '2013-04-01', '17'),
('2012-01-01', '2013-05-05', '5'),
('2020-01-01', '2020-01-01', '5')
;
CREATE TABLE
INSERT 0 7
SELECT s.date1
,COALESCE(t."month2",s.date2) as month2
,t."units"
FROM (
SELECT (t._year || '-01-01') ::date as date1, generate_series( (t._year || '-01-01') ::date
, (date_part('year', CURRENT_DATE) || '-12-01') ::date
, interval '1 month'
)::date AS date2
FROM (SELECT DISTINCT
extract(year from "month1") _year FROM tab1) t
) s
LEFT JOIN tab1 t
ON date_trunc('month',t."month1"::date)::date = s.date1
AND date_trunc('month',t."month2"::date)::date = s.date2
ORDER BY 1,2;
date1
month2
units
2012-01-01
2012-01-01 00:00:00
null
2012-01-01
2012-02-01 00:00:00
null
2012-01-01
2012-03-01 00:00:00
15
2012-01-01
2012-04-01 00:00:00
null
2012-01-01
2012-05-01 00:00:00
null
2012-01-01
2012-06-01 00:00:00
null
2012-01-01
2012-07-01 00:00:00
null
2012-01-01
2012-08-01 00:00:00
null
2012-01-01
2012-09-01 00:00:00
null
2012-01-01
2012-10-01 00:00:00
null
2012-01-01
2012-11-01 00:00:00
null
2012-01-01
2012-12-01 00:00:00
null
2012-01-01
2013-01-01 00:00:00
12
2012-01-01
2013-02-01 00:00:00
null
2012-01-01
2013-03-01 00:00:00
null
2012-01-01
2013-04-01 00:00:00
17
2012-01-01
2013-05-05 00:00:00
5
2012-01-01
2013-06-01 00:00:00
null
2012-01-01
2013-07-01 00:00:00
null
2012-01-01
2013-08-01 00:00:00
null
2012-01-01
2013-09-01 00:00:00
null
2012-01-01
2013-10-01 00:00:00
null
2012-01-01
2013-11-01 00:00:00
null
2012-01-01
2013-12-01 00:00:00
null
2012-01-01
2014-01-01 00:00:00
null
2012-01-01
2014-02-01 00:00:00
null
2012-01-01
2014-03-01 00:00:00
null
2012-01-01
2014-04-01 00:00:00
null
2012-01-01
2014-05-01 00:00:00
null
2012-01-01
2014-06-01 00:00:00
null
2012-01-01
2014-07-01 00:00:00
null
2012-01-01
2014-08-01 00:00:00
null
2012-01-01
2014-09-01 00:00:00
null
2012-01-01
2014-10-01 00:00:00
null
2012-01-01
2014-11-01 00:00:00
null
2012-01-01
2014-12-01 00:00:00
null
2012-01-01
2015-01-01 00:00:00
null
2012-01-01
2015-02-01 00:00:00
null
2012-01-01
2015-03-01 00:00:00
null
2012-01-01
2015-04-01 00:00:00
null
2012-01-01
2015-05-01 00:00:00
null
2012-01-01
2015-06-01 00:00:00
null
2012-01-01
2015-07-01 00:00:00
null
2012-01-01
2015-08-01 00:00:00
null
2012-01-01
2015-09-01 00:00:00
null
2012-01-01
2015-10-01 00:00:00
null
2012-01-01
2015-11-01 00:00:00
null
2012-01-01
2015-12-01 00:00:00
null
2012-01-01
2016-01-01 00:00:00
null
2012-01-01
2016-02-01 00:00:00
null
2012-01-01
2016-03-01 00:00:00
null
2012-01-01
2016-04-01 00:00:00
null
2012-01-01
2016-05-01 00:00:00
null
2012-01-01
2016-06-01 00:00:00
null
2012-01-01
2016-07-01 00:00:00
null
2012-01-01
2016-08-01 00:00:00
null
2012-01-01
2016-09-01 00:00:00
null
2012-01-01
2016-10-01 00:00:00
null
2012-01-01
2016-11-01 00:00:00
null
2012-01-01
2016-12-01 00:00:00
null
2012-01-01
2017-01-01 00:00:00
null
2012-01-01
2017-02-01 00:00:00
null
2012-01-01
2017-03-01 00:00:00
null
2012-01-01
2017-04-01 00:00:00
null
2012-01-01
2017-05-01 00:00:00
null
2012-01-01
2017-06-01 00:00:00
null
2012-01-01
2017-07-01 00:00:00
null
2012-01-01
2017-08-01 00:00:00
null
2012-01-01
2017-09-01 00:00:00
null
2012-01-01
2017-10-01 00:00:00
null
2012-01-01
2017-11-01 00:00:00
null
2012-01-01
2017-12-01 00:00:00
null
2012-01-01
2018-01-01 00:00:00
null
2012-01-01
2018-02-01 00:00:00
null
2012-01-01
2018-03-01 00:00:00
null
2012-01-01
2018-04-01 00:00:00
null
2012-01-01
2018-05-01 00:00:00
null
2012-01-01
2018-06-01 00:00:00
null
2012-01-01
2018-07-01 00:00:00
null
2012-01-01
2018-08-01 00:00:00
null
2012-01-01
2018-09-01 00:00:00
null
2012-01-01
2018-10-01 00:00:00
null
2012-01-01
2018-11-01 00:00:00
null
2012-01-01
2018-12-01 00:00:00
null
2012-01-01
2019-01-01 00:00:00
null
2012-01-01
2019-02-01 00:00:00
null
2012-01-01
2019-03-01 00:00:00
null
2012-01-01
2019-04-01 00:00:00
null
2012-01-01
2019-05-01 00:00:00
null
2012-01-01
2019-06-01 00:00:00
null
2012-01-01
2019-07-01 00:00:00
null
2012-01-01
2019-08-01 00:00:00
null
2012-01-01
2019-09-01 00:00:00
null
2012-01-01
2019-10-01 00:00:00
null
2012-01-01
2019-11-01 00:00:00
null
2012-01-01
2019-12-01 00:00:00
null
2012-01-01
2020-01-01 00:00:00
null
2012-01-01
2020-02-01 00:00:00
null
2012-01-01
2020-03-01 00:00:00
null
2012-01-01
2020-04-01 00:00:00
null
2012-01-01
2020-05-01 00:00:00
null
2012-01-01
2020-06-01 00:00:00
null
2012-01-01
2020-07-01 00:00:00
null
2012-01-01
2020-08-01 00:00:00
null
2012-01-01
2020-09-01 00:00:00
null
2012-01-01
2020-10-01 00:00:00
null
2012-01-01
2020-11-01 00:00:00
null
2012-01-01
2020-12-01 00:00:00
null
2012-01-01
2021-01-01 00:00:00
null
2012-01-01
2021-02-01 00:00:00
null
2012-01-01
2021-03-01 00:00:00
null
2012-01-01
2021-04-01 00:00:00
null
2012-01-01
2021-05-01 00:00:00
null
2012-01-01
2021-06-01 00:00:00
null
2012-01-01
2021-07-01 00:00:00
null
2012-01-01
2021-08-01 00:00:00
null
2012-01-01
2021-09-01 00:00:00
null
2012-01-01
2021-10-01 00:00:00
null
2012-01-01
2021-11-01 00:00:00
null
2012-01-01
2021-12-01 00:00:00
null
2012-01-01
2022-01-01 00:00:00
null
2012-01-01
2022-02-01 00:00:00
null
2012-01-01
2022-03-01 00:00:00
null
2012-01-01
2022-04-01 00:00:00
null
2012-01-01
2022-05-01 00:00:00
null
2012-01-01
2022-06-01 00:00:00
null
2012-01-01
2022-07-01 00:00:00
null
2012-01-01
2022-08-01 00:00:00
null
2012-01-01
2022-09-01 00:00:00
null
2012-01-01
2022-10-01 00:00:00
null
2012-01-01
2022-11-01 00:00:00
null
2012-01-01
2022-12-01 00:00:00
null
2020-01-01
2020-01-01 00:00:00
5
2020-01-01
2020-02-01 00:00:00
null
2020-01-01
2020-03-01 00:00:00
null
2020-01-01
2020-04-01 00:00:00
null
2020-01-01
2020-05-01 00:00:00
null
2020-01-01
2020-06-01 00:00:00
null
2020-01-01
2020-07-01 00:00:00
null
2020-01-01
2020-08-01 00:00:00
null
2020-01-01
2020-09-01 00:00:00
null
2020-01-01
2020-10-01 00:00:00
null
2020-01-01
2020-11-01 00:00:00
null
2020-01-01
2020-12-01 00:00:00
null
2020-01-01
2021-01-01 00:00:00
null
2020-01-01
2021-02-01 00:00:00
null
2020-01-01
2021-03-01 00:00:00
null
2020-01-01
2021-04-01 00:00:00
null
2020-01-01
2021-05-01 00:00:00
null
2020-01-01
2021-06-01 00:00:00
null
2020-01-01
2021-07-01 00:00:00
null
2020-01-01
2021-08-01 00:00:00
null
2020-01-01
2021-09-01 00:00:00
null
2020-01-01
2021-10-01 00:00:00
null
2020-01-01
2021-11-01 00:00:00
null
2020-01-01
2021-12-01 00:00:00
null
2020-01-01
2022-01-01 00:00:00
null
2020-01-01
2022-02-01 00:00:00
null
2020-01-01
2022-03-01 00:00:00
null
2020-01-01
2022-04-01 00:00:00
null
2020-01-01
2022-05-01 00:00:00
null
2020-01-01
2022-06-01 00:00:00
null
2020-01-01
2022-07-01 00:00:00
null
2020-01-01
2022-08-01 00:00:00
null
2020-01-01
2022-09-01 00:00:00
null
2020-01-01
2022-10-01 00:00:00
null
2020-01-01
2022-11-01 00:00:00
null
2020-01-01
2022-12-01 00:00:00
null
SELECT 168
fiddle

Aggregate only Sequential values

I have a table with 3 columns
Create table test
(
Created Datetime
, Flag Bit
, Amount Money
)
that looks like this
Created Flag Amount
2019-12-01 00:00:00.000 1 50,40
2019-11-21 00:00:00.000 1 50,40
2019-11-06 00:00:00.000 0 50,40
2019-10-04 00:00:00.000 1 50,40
2019-09-08 00:00:00.000 1 50,40
2019-09-01 00:00:00.000 0 50,40
2019-08-04 00:00:00.000 1 50,40
2019-07-24 00:00:00.000 1 50,40
2019-07-23 00:00:00.000 1 50,40
2019-06-01 00:00:00.000 0 50,40
2019-05-05 00:00:00.000 0 50,40
2019-04-25 00:00:00.000 1 50,40
2019-03-11 00:00:00.000 0 50,40
2019-02-03 00:00:00.000 0 50,40
2019-02-02 00:00:00.000 0 50,40
2019-02-01 00:00:00.000 0 50,40
2019-01-31 00:00:00.000 1 50,40
2019-01-26 00:00:00.000 0 50,40
2019-01-26 00:00:00.000 0 50,40
2019-01-01 00:00:00.000 1 50,40
As you can see it is ordered by Created in descending order.
Imagine that all these rows are Transactions. When the flag is one we have a checkpoint. So for example from line 20 to 17 is one period(Always counting from older to newer). From line 17 to 12 is another period and so on.
Please notice that in lines 9,8 and 7 we have 3 consecutive flags with a value of 1. When this happens, having consecutive 1s without 0s, i want to treat all the consecutive 1s as a group. I want them to appear as one row with Summed amount and keeping the MIN(Created) of them.
For example for rows 9-7 I want to group it in one row with where amount has a value of 151.2,flag a value of 1 and Created a value of 2019-07-23 00:00:00.000 (the min(date) of the three rows.
An example output of this table would be the following.
Created Flag Amount
2019-11-21 00:00:00.000 1 100,80
2019-11-06 00:00:00.000 0 50,40
2019-09-08 00:00:00.000 1 100,80
2019-09-01 00:00:00.000 0 50,40
2019-07-23 00:00:00.000 1 151,20
2019-06-01 00:00:00.000 0 50,40
2019-05-05 00:00:00.000 0 50,40
2019-04-25 00:00:00.000 1 50,40
2019-03-11 00:00:00.000 0 50,40
2019-02-03 00:00:00.000 0 50,40
2019-02-02 00:00:00.000 0 50,40
2019-02-01 00:00:00.000 0 50,40
2019-01-31 00:00:00.000 1 50,40
2019-01-26 00:00:00.000 0 50,40
2019-01-26 00:00:00.000 0 50,40
2019-01-01 00:00:00.000 1 50,40
If you just want to collapse adjacent "1"s, then one approach is to assign a grouping based on the count of preceding 0s and aggregate. So for aggregating the "1"s:
select min(created), 1 as flag, sum(amount)
from (select t.*,
sum(1 - flag) over (order by created) as grouping
from t
) t
where flag = 1
group by grouping;
This does not quite work when we include 0s, because the 0s would get combined with the 1s. So I think the simplest method is union all:
select min(created), 1 as flag, sum(amount)
from (select t.*,
sum(1 - flag) over (order by created) as grouping
from t
) t
where flag = 1
group by grouping
union all
select created, flag, amount
from t
where flag = 0;
I originally misinterpreted the question as wanting a summary for all periods, not just the adjacent "1"s. You can do this with a cumulative sum to identify the groups:
select t.*,
sum(flag) over (order by created) as grouping
from t;
And then use a subquery to aggregate this:
select min(created), max(created), count(*) as num_transactions,
sum(amount) as total_amount
from (select t.*,
sum(flag) over (order by created) as grouping
from t
) t
group by grouping;
You want to aggregate all consecutive rows flagged 1. You can achieve this with a running count of rows flagged 0. You can see in the table below that flag + running count of zeros identifies the groups.
Created | Amount | Flag | COUNT_0
-----------+--------+------+--------
2019-12-01 | 50,40 | 1 | 0 \ both rows flag=1, count_0=0 => one group
2019-11-21 | 50,40 | 1 | 0 /
2019-11-06 | 50,40 | 0 | 1 > the only row with flag=0, count_0=1 => one group
2019-10-04 | 50,40 | 1 | 1 \ both rows flag=1, count_0=1 => one group
2019-09-08 | 50,40 | 1 | 1 /
2019-09-01 | 50,40 | 0 | 2 > the only row with flag=0, count_0=2 => one group
2019-08-04 | 50,40 | 1 | 2 \
2019-07-24 | 50,40 | 1 | 2 | all three rows flag=1, count_0=2 => one group
2019-07-23 | 50,40 | 1 | 2 /
2019-06-01 | 50,40 | 0 | 3 > the only row with flag=0, count_0=3 => one group
2019-05-05 | 50,40 | 0 | 4 > the only row with flag=0, count_0=4 => one group
2019-04-25 | 50,40 | 1 | 4 > the only row with flag=1, count_0=4 => one group
2019-03-11 | 50,40 | 0 | 5 > the only row with flag=0, count_0=5 => one group
2019-02-03 | 50,40 | 0 | 6 > the only row with flag=0, count_0=6 => one group
2019-02-02 | 50,40 | 0 | 7 > the only row with flag=0, count_0=7 => one group
2019-02-01 | 50,40 | 0 | 8 > the only row with flag=0, count_0=8 => one group
2019-01-31 | 50,40 | 1 | 8 > the only row with flag=1, count_0=8 => one group
2019-01-26 | 50,40 | 0 | 9 > the only row with flag=0, count_0=9 => one group
2019-01-26 | 50,40 | 0 | 10 > the only row with flag=0, count_0=10 => one group
2019-01-01 | 50,40 | 1 | 10 > the only row with flag=1, count_0=10 => one group
The related query:
select min(created), min(flag), sum(amount)
from
(
select
m.*,
count(case when flag = 0 then 1 end) over (order by created) as count_0
from mytable m
)
group by flag, count_0
order by min(created);

SQL - Compare rows by id, date and amount

I need to SELECT a row in which issue_date = maturity_date of another row with same id, and same amount_usd.
I tried with self join, but I do not get right result.
Here is a simplified version of my table:
ID ISSUE_DATE MATURITY_DATE AMOUNT_USD
1 2010-01-01 00:00:00.000 2015-12-01 00:00:00.000 5000
1 2010-01-01 00:00:00.000 2001-09-19 00:00:00.000 700
2 2014-04-09 00:00:00.000 2019-04-09 00:00:00.000 400
1 2015-12-01 00:00:00.000 2016-12-31 00:00:00.000 5000
5 2015-02-24 00:00:00.000 2015-02-24 00:00:00.000 8000
4 2012-11-29 00:00:00.000 2015-11-29 00:00:00.000 10000
3 2015-01-21 00:00:00.000 2018-01-21 00:00:00.000 17500
2 2015-02-02 00:00:00.000 2015-12-05 00:00:00.000 12000
1 2015-01-12 00:00:00.000 2018-01-12 00:00:00.000 18000
2 2015-12-05 00:00:00.000 2016-01-10 00:00:00.000 12000
Result should be:
ID ISSUE_DATE MATURITY_DATE AMOUNT_USD
1 2015-12-01 00:00:00.000 2016-12-31 00:00:00.000 5000
2 2015-12-05 00:00:00.000 2016-01-10 00:00:00.000 12000
Thanks in advance!
Do following: http://sqlfiddle.com/#!6/c0a02/1
select a.id, a.issue_date, a.maturity_date, a.amount_usd
from tbl a
inner join tbl b
on a.id = b.id
and a.maturity_date = b.issue_date
-- added to prevent same maturity date and issue date
where a.maturity_date <> a.issue_date
Output:
| id | issue_date | maturity_date | amount_usd |
|----|----------------------------|----------------------------|------------|
| 1 | January, 01 2010 00:00:00 | December, 01 2015 00:00:00 | 5000 |
| 2 | February, 02 2015 00:00:00 | December, 05 2015 00:00:00 | 12000 |

How to sort data based on two columns by grouping on one column among them?

I have the following set of data.
select * from STATEMENT_HISTORY(nolock) order by stmt_dte desc
stmt_key stmt_dte stmt_start_dte stmt_end_dte
----------- ----------------------- ----------------------- -----------------------
12 2013-10-13 00:00:00.000 2013-07-10 00:00:00.000 2013-08-10 00:00:00.000
11 2013-10-12 00:00:00.000 2013-03-10 00:00:00.000 2013-04-10 00:00:00.000
10 2013-10-11 00:00:00.000 2013-07-10 00:00:00.000 2013-08-10 00:00:00.000
9 2013-10-10 00:00:00.000 2013-09-10 00:00:00.000 2013-10-10 00:00:00.000
8 2013-09-10 00:00:00.000 2013-08-10 00:00:00.000 2013-09-10 00:00:00.000
7 2013-08-10 00:00:00.000 2013-07-10 00:00:00.000 2013-08-10 00:00:00.000
6 2013-07-10 00:00:00.000 2013-06-10 00:00:00.000 2013-07-10 00:00:00.000
5 2013-06-10 00:00:00.000 2013-05-10 00:00:00.000 2013-06-10 00:00:00.000
4 2013-05-10 00:00:00.000 2013-04-10 00:00:00.000 2013-05-10 00:00:00.000
3 2013-04-10 00:00:00.000 2013-03-10 00:00:00.000 2013-04-10 00:00:00.000
2 2013-03-10 00:00:00.000 2013-02-10 00:00:00.000 2013-03-10 00:00:00.000
1 2013-02-10 00:00:00.000 2013-01-10 00:00:00.000 2013-02-10 00:00:00.000
My requirement is as follows.
1. The row with latest stmt_dte should be on top
2. All other rows that match with the stmt_start_dte of the top row should take next place sorted by stmt_dte among them and so on.
Expected output should be in the following order.
stmt_key
--------
12
10
7
11
3
10
9
8
6
5
4
2
1
How do I achieve it? Can some one suggest a better approach?
You seem to be using SQL Server. The logic appears to be:
Keep the records with the same stmt_start_dte together
Order them by the maximum stmt_dte
You can do this by using the max() window function:
select stmt_key, stmt_dte, stmt_start_dte, stmt_end_dte
from (select sh.*, max(stmt_dte) over (partition by stmt_start_dte) as grp
from STATEMENT_HISTORY sh
) sh
order by grp desc, stmt_dte desc;

SQL query hourly for each day

I have a question that seems to be quite complex. I needed to know what happens in a session that day, at a certain time.
Briefly I have a table that shows me all sessions of a given area. These sessions have a start date and a start time and an end time.
You can see in this table:
idArea | idSession | startDate | startTime | endTime
1 | 1 | 2013-01-01 | 1900-01-01 09:00:00 | 1900-01-01 12:00:00
1 | 2 | 2013-01-01 | 1900-01-01 14:00:00 | 1900-01-01 15:00:00
1 | 3 | 2013-01-04 | 1900-01-01 09:00:00 | 1900-01-01 13:00:00
1 | 4 | 2013-01-07 | 1900-01-01 10:00:00 | 1900-01-01 12:00:00
1 | 5 | 2013-01-07 | 1900-01-01 13:00:00 | 1900-01-01 18:00:00
1 | 6 | 2013-01-08 | 1900-01-01 10:00:00 | 1900-01-01 12:00:00
Then I also have a table that shows me all hours interspersed, ie every half hour (I created this table on purpose for this requirement, if someone has a better idea, I can say that I will try to adapt).
idHour | Hour
1 | 1900-01-01 00:00:00
2 | 1900-01-01 00:30:00
3 | 1900-01-01 01:00:00
............................
4 | 1900-01-01 09:00:00
5 | 1900-01-01 09:30:00
6 | 1900-01-01 10:00:00
7 | 1900-01-01 10:30:00
............................
In the end that's what I want to present was this:
startDate | startTime | SessionID
2013-01-01 | 1900-01-01 09:00:00 | 1
2013-01-01 | 1900-01-01 09:30:00 | 1
2013-01-01 | 1900-01-01 10:00:00 | 1
2013-01-01 | 1900-01-01 10:30:00 | 1
2013-01-01 | 1900-01-01 11:00:00 | 1
2013-01-01 | 1900-01-01 11:30:00 | 1
2013-01-01 | 1900-01-01 11:30:00 | 1
2013-01-01 | 1900-01-01 14:00:00 | 1
2013-01-01 | 1900-01-01 14:30:00 | 1
2013-01-01 | 1900-01-01 15:00:00 | 1
This table is only for idSession=1 what I wanted was for all sessions. If there are no sessions for one day can return NULL.
The hard this query or procedure, is that they have to show me all the days of the month when there are sessions for that area.
For this, I already used this query:
;WITH t1 AS
(
SELECT
startDate,
DATEADD(MONTH, DATEDIFF(MONTH, '1900-01-01', startDate), '1900-01-01') firstInMonth,
DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, '1900-01-01', startDate) + 1, '1900-01-01')) lastInMonth,
COUNT(*) cnt
FROM
#SessionsPerArea
WHERE
idArea = 1
GROUP BY
startDate
), calendar AS
(
SELECT DISTINCT
DATEADD(DAY, c.number, t1.firstInMonth) d
FROM
t1
JOIN
master..spt_values c ON type = 'P'
AND DATEADD(DAY, c.number, t1.firstInMonth) BETWEEN t1.firstInMonth AND t1.lastInMonth
)
SELECT
d date,
cnt Session
FROM
calendar c
LEFT JOIN
t1 ON t1.startDate = c.d
It is quite complex, if anyone has an easy way to do this was excellent.
If I understand correctly, this is simply a join between the calendar table and #SessionPerArea,w ith the right conditions:
select spa.StartDate, c.hour as StartTime, spa.idSession as SessionId
from calendar c join
#SessionsPerArea spa
on c.hour between spa.startTime and spa.EndTime
The join is matching all times between the start and end times in the data, and then returning the values.
I think maybe you simply need an outer join between calendar and #SessionsPerArea...so all the days in the calendar table are returned regardless of a match to the #SessionsPerArea table?