Joining two queries together in Oracle SQL - sql

I have 2 queries in Oracle, one gives me information about the jobs, the other gives me a correct (amended) start time and target time to take into account the working day.
The field linking both tables is job.job_number
What I would like to do is have them together so that all the information is provided in one report, but I'm not sure how to do this.
Query 1 code
select
job.job_number,
job.job_entry_date,
job.site_code
from
job
inner join JOB_STATUS_LOG on JOB.JOB_NUMBER = JOB_STATUS_LOG.JOB_NUMBER
and job.job_log_number = job_status_log.job_log_number
inner join JOB_STATUS on JOB_STATUS.STATUS_CODE = JOB_STATUS_LOG.STATUS_CODE
where
job_status_log.allocated_officer = 'IDVE'
and job_status.status_code in ('5100','5200','5300','5400')
order by
job.job_number
Query 1 output
Job Number Job Entry Date Job Site Code
12345 01/08/2019 21:00 1234
67890 01/08/2019 18:00 5678
Query 2 Code
select
job_number,
clock_start,
case
when to_char(target_time, 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') = 'Fri'
and floor((target_time - trunc(target_time)) * 24) >= 17
then target_time + 2 + 63/24
when floor((target_time - trunc(target_time)) * 24) >= 17
then target_time + 15/24
else target_time
end as target_time
from
(
select job_number, priority_code, clock_start,
CASE
WHEN PRIORITY_CODE IN ('GC01','GC02','GC03','GC04','GC05','GC06','GC07')
THEN
clock_start + case priority_code
when 'GC01' then 1
when 'GC02' then 2
when 'GC03' then 0.5
when 'GC04' then 1
when 'GC05' then 2
when 'GC06' then 4
when 'GC07' then 24
end / 24
ELSE TARGET_COMP_DATE END as target_time
from
(
select job_number, priority_code, job_entry_date, target_comp_date,
case
when to_char(job_entry_date, 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') =
'Fri'
and floor((job_entry_date - trunc(job_entry_date)) * 24) >= 17
then trunc(job_entry_date) + 80/24
when to_char(job_entry_date, 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') =
'Sat'
then trunc(job_entry_date) + 56/24
when to_char(job_entry_date, 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') =
'Sun'
or floor((job_entry_date - trunc(job_entry_date)) * 24) >= 17
then trunc(job_entry_date) + 32/24
when floor((job_entry_date - trunc(job_entry_date)) * 24) < 8
then trunc(job_entry_date) + 8/24
else job_entry_date
end as clock_start
from job
)
)
where
priority_code in ('GC01','GC02','GC03','GC04','GC05','GC06','GC07')
Query 2 output
Job Number Clock Start Target Time
12345 02/08/2019 08:00 02/08/2019 10:00
67890 02/08/2019 08:00 02/08/2019 12:00
Required Output
This is how I would like it to appear
Job Number Job Entry Date Job Site Code Clock Start Target Time
12345 01/08/2019 21:00 1234 02/08/2019 08:00 02/08/2019 10:00
67890 01/08/2019 18:00 5678 02/08/2019 08:00 02/08/2019 12:00

One option might be to use current queries as sources for the WITH factoring clause (i.e. the CTE, Common table expression) and join them afterwards. I've shortened your queries (named q1 and q2) to make the example simpler to understand:
WITH q1 AS (SELECT job_number, job_entry_date, site_code FROM some_tables),
q2 AS (SELECT job_number, clock_start, target_time FROM another_tables)
SELECT a.job_number,
a.job_entry_date,
a.site_code,
b.clock_start,
b.target_time
FROM q1 a JOIN q2 b ON a.job_number = b.job_number
As you said that the first word has to be SELECT, no problem - switch to inline views:
SELECT a.job_number,
a.job_entry_date,
a.site_code,
b.clock_start,
b.target_time
FROM (SELECT job_number, job_entry_date, site_code FROM some_tables) a
JOIN
(SELECT job_number, clock_start, target_time FROM another_tables) b
ON a.job_number = b.job_number
I don't know which version it is nor whether it supports such joins; if not, then another option is
...
FROM (SELECT job_number, job_entry_date, site_code FROM some_tables) a,
(SELECT job_number, clock_start, target_time FROM another_tables) b
WHERE a.job_number = b.job_number

As you are basically reading your info's from the job table you might simple pass the additional data through your subselects auf Query 2. The JOINS in Query 1 are only for filtering reasons i think:
select
job_number,
job_entry_date,
site_code,
clock_start,
case
when to_char(target_time, 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') = 'Fri'
and floor((target_time - trunc(target_time)) * 24) >= 17
then target_time + 2 + 63/24
when floor((target_time - trunc(target_time)) * 24) >= 17
then target_time + 15/24
else target_time
end as target_time
from
(
select job_number, job_entry_date, site_code, priority_code, clock_start,
CASE
WHEN PRIORITY_CODE IN ('GC01','GC02','GC03','GC04','GC05','GC06','GC07')
THEN
clock_start + case priority_code
when 'GC01' then 1
when 'GC02' then 2
when 'GC03' then 0.5
when 'GC04' then 1
when 'GC05' then 2
when 'GC06' then 4
when 'GC07' then 24
end / 24
ELSE TARGET_COMP_DATE END as target_time
from
(
select job_number, priority_code, job_entry_date, target_comp_date,
case
when to_char(job_entry_date, 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') =
'Fri'
and floor((job_entry_date - trunc(job_entry_date)) * 24) >= 17
then trunc(job_entry_date) + 80/24
when to_char(job_entry_date, 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') =
'Sat'
then trunc(job_entry_date) + 56/24
when to_char(job_entry_date, 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') =
'Sun'
or floor((job_entry_date - trunc(job_entry_date)) * 24) >= 17
then trunc(job_entry_date) + 32/24
when floor((job_entry_date - trunc(job_entry_date)) * 24) < 8
then trunc(job_entry_date) + 8/24
else job_entry_date
end as clock_start
,site_code
from job
)
)
where
priority_code in ('GC01','GC02','GC03','GC04','GC05','GC06','GC07')

Related

SQL query to change dates during runtime

I have a situation where I need to write a SQL query to get last 10 years of data. For the first release date require last 10 years data and second release dates are mentioned in the picture. Need to automate dates according to the release date. Please help me.
enter image description here
For every release date, dates should automatically changes. Should not be hard-coded dates.
Maybe this could be helpfull:
WITH
release_dates AS -- sample data
( Select Add_Months(SYSDATE, (-10 + LEVEL)) - (LEVEL * 3) "RELEASE_DATE" From Dual Connect By LEVEL <= 9 )
SELECT
RELEASE_DATE,
--
ADD_MONTHS(
CASE WHEN To_Char(RELEASE_DATE, 'dd') <= 20 THEN LAST_DAY(ADD_MONTHS(RELEASE_DATE, -1))
ELSE LAST_DAY(RELEASE_DATE)
END + 1
, - 120) "START_DATE",
--
CASE WHEN To_Char(RELEASE_DATE, 'dd') <= 20 THEN LAST_DAY(ADD_MONTHS(RELEASE_DATE, -1))
ELSE LAST_DAY(RELEASE_DATE)
END "END_DATE",
--
To_Char(
ADD_MONTHS(
CASE WHEN To_Char(RELEASE_DATE, 'dd') <= 20 THEN LAST_DAY(ADD_MONTHS(RELEASE_DATE, -1))
ELSE LAST_DAY(RELEASE_DATE)
END + 1
, - 120)
, 'dd-MON-yy') || ' - ' ||
To_Char(RELEASE_DATE, 'dd-MON-yy')"DATA_REFRESH_DATES"
FROM
release_dates
R e s u l t :
RELEASE_DATE
START_DATE
END_DATE
DATA_REFRESH_DATES
18-MAR-22
01-MAR-12
28-FEB-22
01-MAR-12 - 18-MAR-22
15-APR-22
01-APR-12
31-MAR-22
01-APR-12 - 15-APR-22
12-MAY-22
01-MAY-12
30-APR-22
01-MAY-12 - 12-MAY-22
09-JUN-22
01-JUN-12
31-MAY-22
01-JUN-12 - 09-JUN-22
06-JUL-22
01-JUL-12
30-JUN-22
01-JUL-12 - 06-JUL-22
03-AUG-22
01-AUG-12
31-JUL-22
01-AUG-12 - 03-AUG-22
31-AUG-22
01-SEP-12
31-AUG-22
01-SEP-12 - 31-AUG-22
27-SEP-22
01-OCT-12
30-SEP-22
01-OCT-12 - 27-SEP-22
25-OCT-22
01-NOV-12
31-OCT-22
01-NOV-12 - 25-OCT-22

calculate column names automatically sql

Is there a way to calculate column names automatically in SQL like below. I need top calculate the Calendar weeks based on from and to date and distribute evenly
Material
From
To
Sales
M01
03.10.2022
31.10.2022
1000
M02
14.11.2022
28.11.2022
1000
Expected output
CW =calendar week
Material
Cw40
CW41
Cw42
CW43
CW44
CW45
CW46
CW47
M01
250
250
250
250
M02
500
500
Is there a way to calculate column names automatically in SQL like below.
No, in SQL (not just Oracle SQL) you needs a fixed, known number of column names so it is impossible to dynamically generate columns with a static SQL query.
If you want to generate the data then either:
Generate the data as rows (rather than columns) and pivot the result in whatever third-party application you are using to access the database. You can generate the output using a correlated row-generator:
SELECT t.material,
w.iso_year,
w.iso_week,
w.weekly_sales
FROM table_name t
CROSS APPLY (
SELECT TO_NUMBER(
TO_CHAR(
TRUNC(from_dt, 'IW') + INTERVAL '7' DAY * (LEVEL - 1),
'IYYY'
)
) AS iso_year,
TO_NUMBER(
TO_CHAR(
TRUNC(from_dt, 'IW') + INTERVAL '7' DAY * (LEVEL - 1),
'IW'
)
) AS iso_week,
( LEAST(
TRUNC(from_dt, 'IW') + INTERVAL '7' DAY * LEVEL,
to_dt
)
- GREATEST(
TRUNC(from_dt, 'IW') + INTERVAL '7' DAY * (LEVEL - 1),
from_dt
)
) / (to_dt - from_dt) * sales AS weekly_sales
FROM DUAL
CONNECT BY TRUNC(from_dt, 'IW') + INTERVAL '7' DAY * (LEVEL-1) < to_dt
) w
or:
WITH data (from_dt, dt, to_dt, material, sales) AS (
SELECT from_dt, from_dt, to_dt, material, sales
FROM table_name
UNION ALL
SELECT from_dt,
TRUNC(dt + INTERVAL '7' DAY, 'IW'),
to_dt,
material,
sales
FROM data
WHERE TRUNC(dt + INTERVAL '7' DAY, 'IW') < to_dt
)
SELECT material,
TO_NUMBER(TO_CHAR(dt, 'IYYY')) AS iso_year,
TO_NUMBER(TO_CHAR(dt, 'IW')) AS iso_week,
( LEAST(dt + INTERVAL '7' DAY, to_dt) - dt)
/ (to_dt - from_dt) * sales AS weekly_sales
FROM data
Which, for the sample data:
CREATE TABLE table_name (Material, From_dt, To_dt, Sales) AS
SELECT 'M01', DATE '2022-10-03', DATE '2022-10-31', 1000 FROM DUAL UNION ALL
SELECT 'M02', DATE '2022-11-14', DATE '2022-11-28', 1000 FROM DUAL;
Both output:
MATERIAL
ISO_YEAR
ISO_WEEK
WEEKLY_SALES
M01
2022
40
250
M01
2022
41
250
M01
2022
42
250
M01
2022
43
250
M02
2022
46
500
M02
2022
47
500
Or, if you did want to output the values as columns then you need to specify the columns (which would be 53 columns for all 53 potential ISO weeks) and can do that using:
SELECT *
FROM (
SELECT t.material,
w.iso_year,
w.iso_week,
w.weekly_sales
FROM table_name t
CROSS APPLY (
SELECT TO_NUMBER(
TO_CHAR(
TRUNC(from_dt, 'IW') + INTERVAL '7' DAY * (LEVEL - 1),
'IYYY'
)
) AS iso_year,
TO_NUMBER(
TO_CHAR(
TRUNC(from_dt, 'IW') + INTERVAL '7' DAY * (LEVEL - 1),
'IW'
)
) AS iso_week,
( LEAST(
TRUNC(from_dt, 'IW') + INTERVAL '7' DAY * LEVEL,
to_dt
)
- GREATEST(
TRUNC(from_dt, 'IW') + INTERVAL '7' DAY * (LEVEL - 1),
from_dt
)
) / (to_dt - from_dt) * sales AS weekly_sales
FROM DUAL
CONNECT BY TRUNC(from_dt, 'IW') + INTERVAL '7' DAY * (LEVEL-1) < to_dt
) w
)
PIVOT (
SUM(weekly_sales)
FOR iso_week IN (
1 AS cw01,
2 AS cw02,
3 AS cw03,
-- ...
40 AS cw40,
41 AS cw41,
42 AS cw42,
43 AS cw43,
44 AS cw44,
45 AS cw45,
46 AS cw46,
47 AS cw47,
48 AS cw48,
49 AS cw49,
50 AS cw50,
51 AS cw51,
52 AS cw52,
53 AS cw53
)
)
or:
WITH data (from_dt, dt, to_dt, material, sales) AS (
SELECT from_dt, from_dt, to_dt, material, sales
FROM table_name
UNION ALL
SELECT from_dt,
TRUNC(dt + INTERVAL '7' DAY, 'IW'),
to_dt,
material,
sales
FROM data
WHERE TRUNC(dt + INTERVAL '7' DAY, 'IW') < to_dt
)
SELECT *
FROM (
SELECT material,
TO_NUMBER(TO_CHAR(dt, 'IYYY')) AS iso_year,
TO_NUMBER(TO_CHAR(dt, 'IW')) AS iso_week,
( LEAST(dt + INTERVAL '7' DAY, to_dt) - dt)
/ (to_dt - from_dt) * sales AS weekly_sales
FROM data
)
PIVOT (
SUM(weekly_sales)
FOR iso_week IN (
1 AS cw01,
2 AS cw02,
3 AS cw03,
-- ...
40 AS cw40,
41 AS cw41,
42 AS cw42,
43 AS cw43,
44 AS cw44,
45 AS cw45,
46 AS cw46,
47 AS cw47,
48 AS cw48,
49 AS cw49,
50 AS cw50,
51 AS cw51,
52 AS cw52,
53 AS cw53
)
)
Which both output:
MATERIAL
ISO_YEAR
CW01
CW02
CW03
CW40
CW41
CW42
CW43
CW44
CW45
CW46
CW47
CW48
CW49
CW50
CW51
CW52
CW53
M01
2022
null
null
null
250
250
250
250
null
null
null
null
null
null
null
null
null
null
M02
2022
null
null
null
null
null
null
null
null
null
500
500
null
null
null
null
null
null
fiddle

Cumulative sum group by 15 min interval - Oracle SQL

I would like to get the cumulative sum group by 15 min interval.
eg:
table name: myTable
id name start_time faults
============================================
1 a 06/07/19 23:30 1
2 b 06/07/19 23:35 1
3 c 06/07/19 23:36 1
4 d 06/07/19 23:50 1
5 e 06/07/19 23:54 1
6 f 07/07/19 00:05 1
7 g 07/07/19 00:20 1
8 h 07/07/19 00:25 1
Result:
start_Time faults
============================================
06/07/19 23:15 0
06/07/19 23:30 3
06/07/19 23:45 5
06/07/19 00:00 6
07/07/19 00:15 8
07/07/19 00:30 8
08/07/19 00:45 8
08/07/19 01:00 8
thanks
I think you want:
select trunc(start_time, 'hh') + (floor(extract(minute from start_time) / 15) * 15) * interval '1' minute as dte,
sum(count(*)) over (order by min(start_time))
from t
group by trunc(start_time, 'hh') + (floor(extract(minute from start_time) / 15) * 15) * interval '1' minute
order by dte;
Here is a db<>fiddle.
This query gives cumulative sums for existing quarters:
dbfiddle
select date '1900-01-01' + tm / 24 / 4 tm, sum(sum(faults)) over (order by tm) faults
from (select floor((start_time - date '1900-01-01') * 24 * 4) tm, faults from mytable)
group by tm
If you want wider date range then generate it using connect by query and join with above using lag() with ignore nulls, like here:
with
flts as (
select date '1900-01-01' + tm / 24 / 4 tm, sum(sum(faults)) over (order by tm) faults
from (select floor((start_time - date '1900-01-01') * 24 * 4) tm, faults from mytable)
group by tm),
quarters as (
select to_date('2019-07-06 23:00', 'yyyy-mm-dd hh24:mi') + level * interval '15' minute tm
from dual connect by level <= 10 )
select to_char(tm, 'yyyy-mm-dd hh24:mi') tm,
nvl(faults, lag(faults, 1, 0) ignore nulls over (order by tm))
from quarters left join flts using (tm)
You can achieve it using group by with dates truncated to 15 mins and then using analytical function to calculate the cumulative sum as following:
Select
start_time
+ 15/1440
- mod((start_time - trunc(start_time)) * 1440, 15)/1440,
sum(count(1)) over (order by min(start_time))
from your_table
Group by start_time
+ 15/1440
- mod((start_time - trunc(start_time)) * 1440, 15)/1440
It is same as gordon's answer but using arithmetics. :)
Cheers!!

Multiple row to multiple column based on data in SQL Oracle

output will be as image
SQL Oracle query Sample
select * from (
select * from (
with fifteen as (select trunc(sysdate) + (level * 15)/(24*60) c_time from dual connect by level <= (24*60) / 15 )
select to_number(to_char(c_time, 'hh')) HR,to_char(c_time, 'hh24:mi')||' - '||to_char(c_time+ 15 / (24 * 60), 'hh24:mi') TimeSlots
from fifteen
where extract(hour from cast (c_time as timestamp)) between 2 and 5
) t
)
Oracle Query 1:
with fifteen as (
select CAST( TRUNC( sysdate ) AS TIMESTAMP ) + level * INTERVAL '15' MINUTE c_time,
MOD( LEVEL,4 ) AS quarter
from dual
connect by level <= (24*60) / 15
)
SELECT "2", "3", "4", "5"
FROM (
select EXTRACT( HOUR FROM c_time ) HR,
quarter,
to_char(c_time, 'hh24:mi')||' - '||to_char(c_time + INTERVAL '15' MINUTE, 'hh24:mi') TimeSlots
from fifteen
) t
PIVOT( MAX( timeslots ) FOR HR IN ( 2, 3, 4, 5 ) )
ORDER BY quarter
Oracle Query 2:
SELECT TO_CHAR(two, 'HH24:MI') || ' - ' || TO_CHAR(two +INTERVAL '15' MINUTE,'HH24:MI') AS "2",
TO_CHAR(three,'HH24:MI') || ' - ' || TO_CHAR(three+INTERVAL '15' MINUTE,'HH24:MI') AS "3",
TO_CHAR(four ,'HH24:MI') || ' - ' || TO_CHAR(four +INTERVAL '15' MINUTE,'HH24:MI') AS "4",
TO_CHAR(five ,'HH24:MI') || ' - ' || TO_CHAR(five +INTERVAL '15' MINUTE,'HH24:MI') AS "5"
FROM (
SELECT DATE '1970-01-01' + INTERVAL '2' HOUR + INTERVAL '15' MINUTE * (LEVEL - 1) AS two,
DATE '1970-01-01' + INTERVAL '3' HOUR + INTERVAL '15' MINUTE * (LEVEL - 1) AS three,
DATE '1970-01-01' + INTERVAL '4' HOUR + INTERVAL '15' MINUTE * (LEVEL - 1) AS four,
DATE '1970-01-01' + INTERVAL '5' HOUR + INTERVAL '15' MINUTE * (LEVEL - 1) AS five
FROM DUAL
CONNECT BY LEVEL <= 4
)
Output:
2 3 4 5
------------- ------------- ------------- -------------
02:00 - 02:15 03:00 - 03:15 04:00 - 04:15 05:00 - 05:15
02:15 - 02:30 03:15 - 03:30 04:15 - 04:30 05:15 - 05:30
02:30 - 02:45 03:30 - 03:45 04:30 - 04:45 05:30 - 05:45
02:45 - 03:00 03:45 - 04:00 04:45 - 05:00 05:45 - 06:00

Count the number of 7AM or 7PM occurrences between two datetimes

Is there an easy way to do this? By fully between, I mean don't count the 7am or 7pm datetimes that are equal to the start or end time.
I imagine this can be done using the unix timestamp in seconds and a bit of algebra, but I can't figure it out.
I'm happy to use something in PLSQL or plain SQL.
Examples:
start end num_7am_7pm_between_dates
2012-06-16 05:00 2012-06-16 08:00 1
2012-06-16 16:00 2012-06-16 20:00 1
2012-06-16 05:00 2012-06-16 07:00 0
2012-06-16 07:00 2012-06-16 19:00 0
2012-06-16 08:00 2012-06-16 15:00 0
2012-06-16 05:00 2012-06-16 19:01 2
2012-06-16 05:00 2012-06-18 20:00 6
I think this could be reduced further but I don't have Oracle at my disposal to completely test this Oracle SQL:
SELECT StartDate
, EndDate
, CASE WHEN TRUNC(EndDate) - TRUNC(StartDate) < 1
AND TO_CHAR(EndDate, 'HH24') > 19
AND TO_CHAR(StartDate, 'HH24') < 7
THEN 2
WHEN TRUNC(EndDate) - TRUNC(StartDate) < 1
AND (TO_CHAR(EndDate, 'HH24') > 19
OR TO_CHAR(StartDate, 'HH24') < 7)
THEN 1
WHEN TRUNC(EndDate) - TRUNC(StartDate) > 0
AND TO_CHAR(EndDate, 'HH24') > 19
AND TO_CHAR(StartDate, 'HH24') < 7
THEN 2 + ((TRUNC(EndDate) - TRUNC(StartDate)) * 2)
WHEN TRUNC(EndDate) - TRUNC(StartDate) > 0
AND TO_CHAR(EndDate, 'HH24') > 19
OR TO_CHAR(StartDate, 'HH24') < 7
THEN 1 + ((TRUNC(EndDate) - TRUNC(StartDate)) * 2)
ELSE 0
END
FROM MyTable;
Thanks to #A.B.Cade for the Fiddle, it looks like my CASE Logic can be condensed further to:
SELECT SDate
, EDate
, CASE WHEN TO_CHAR(EDate, 'HH24') > 19
AND TO_CHAR(SDate, 'HH24') < 7
THEN 2 + ((TRUNC(EDate) - TRUNC(SDate)) * 2)
WHEN TO_CHAR(EDate, 'HH24') > 19
OR TO_CHAR(SDate, 'HH24') < 7
THEN 1 + ((TRUNC(EDate) - TRUNC(SDate)) * 2)
ELSE 0
END AS MyCalc2
FROM MyTable;
I had fun writing the following solution:
with date_range as (
select min(sdate) as sdate, max(edate) as edate
from t
),
all_dates as (
select sdate + (level-1)/24 as hour
from date_range
connect by level <= (edate-sdate) * 24 + 1
),
counts as (
select t.id, count(*) as c
from all_dates, t
where to_char(hour, 'HH') = '07'
and hour > t.sdate and hour < t.edate
group by t.id
)
select t.sdate, t.edate, nvl(counts.c, 0)
from t, counts
where t.id = counts.id(+)
order by t.id;
I added an id column to the table in case the range of dates aren't unique.
http://www.sqlfiddle.com/#!4/5fa19/13
This may not have the best performance but might work for you:
select sdate, edate, count(*)
from (select distinct edate, sdate, sdate + (level / 24) hr
from t
connect by sdate + (level / 24) <= edate )
where to_char(hr, 'hh') = '07'
group by sdate, edate
UPDATE: As to #FlorinGhita's comment - fixed the query to include zero occurences
select sdate, edate, sum( decode(to_char(hr, 'hh'), '07',1,0))
from (select distinct edate, sdate, sdate + (level / 24) hr
from t
connect by sdate + (level / 24) <= edate )
group by sdate, edate
Do like this (in SQL)
declare #table table ( start datetime, ends datetime)
insert into #table select'2012-06-16 05:00','2012-06-16 08:00' --1
insert into #table select'2012-06-16 16:00','2012-06-16 20:00' --1
insert into #table select'2012-06-16 05:00','2012-06-16 07:00' --0
insert into #table select'2012-06-16 07:00','2012-06-16 19:00' --0
insert into #table select'2012-06-16 08:00','2012-06-16 15:00' --0
insert into #table select'2012-06-16 05:00','2012-06-16 19:01' --2
insert into #table select'2012-06-16 05:00','2012-06-18 20:00' --6
insert into #table select'2012-06-16 07:00','2012-06-18 07:00' --3
Declare #From DATETIME
Declare #To DATETIME
select #From = MIN(start) from #table
select #To = max(ends) from #table
;with CTE AS
(
SELECT distinct
DATEADD(DD,DATEDIFF(D,0,start),0)+'07:00' AS AimTime
FROM #table
),CTE1 AS
(
Select AimTime
FROM CTE
UNION ALL
Select DATEADD(hour, 12, AimTime)
From CTE1
WHERE AimTime< #To
)
select start,ends, count(AimTime)
from CTE1 right join #table t
on t.start < CTE1.AimTime and t.ends > CTE1.AimTime
group by start,ends