Display Records Up to a Certain Time Period Only - sql

I am organizing my dataset into 3 time intervals/shifts of 8:00am, 4:30pm, and 8:30pm as follows:
CASE
WHEN cast(last_update_date as time) >= '20:31' THEN '8:00'
WHEN cast(last_update_date as time) < '8:01' THEN 'As of 08:00'
WHEN cast(last_update_date as time) >= '8:01' AND cast(last_update_date as
time) < '16:31' THEN 'As of 16:30'
WHEN cast(last_update_date as time) >='16:31' and cast(last_update_date as
time) < '20:31' THEN 'As of 20:30'
END TimeInterval
The issue I am having is I don't want to show records in a time interval that has not been completed yet.
So for example, if I run my query at 8:02AM, the records that were updated at 8:01 and 8:02AM will be placed in the "as of 4:30pm" group. But 4:30pm has not "passed" yet, so these records cannot be shown in my dataset.
This also needs to be day-sensitive. For example, if I run my query at 8:02AM on Tuesday, I need to see all the records that occurred Monday, then the records to 8:00AM on Tuesday, but not after. I have already restricted my data to show only for the current week so I do not need to account for previous weeks, just the week starting Monday.
I've been able to do the second part of this by checking the day of the week of the getdate() and comparing to my update date day using the following:
datepart(weekday, getdate()) today_day, datepart(weekday, last_update_date) update_day
then in my where clause I use
today_day <= update_day
This will show today's data as well as the previous days of the week
I tried to do the same approach with the time where I get today's time:
cast(getdate() as time) today_time
But I was unable to write case statements to change to do my comparison to the update date time. ie. I cannot do this in my case statements, or change a time stamp to a specific time stamp for example:
WHEN cast(last_update_date as time) >= '20:31' THEN cast('8:00' as time)
Below is the final output (that is put into Crytal report). In this case, the report was run on Thursday sometime in the morning, we do not want to show those circled numbers until 4:30pm has actually happened on Thursday, even if the user runs the report.
Below is my working query (there is a bunch of other stuff)
IF OBJECT_ID('tempdb..#Final') IS NOT NULL DROP Table #Final
SELECT getdate() today_date, cast(getdate() as time) today_time,
datepart(weekday, getdate()) today_day,
DateName(weekday, last_update_date) Day_of_week_name, datepart(weekday,
last_update_date) update_day, cast(last_update_date as time) last_update_date_Time,
CASE
WHEN cast(last_update_date as time) >= '20:31' THEN '8:00'
WHEN cast(last_update_date as time) < '8:01' THEN 'As of 08:00'
WHEN cast(last_update_date as time) >= '8:01' AND cast(last_update_date as time)
< '16:31' THEN 'As of 16:30'
WHEN cast(last_update_date as time) >='16:31' and cast(last_update_date as time)
< '20:31' THEN 'As of 20:30'
END TimeInterval
,
CASE
WHEN cast(last_update_date as time) >= '20:31' THEN '08:00'
WHEN cast(last_update_date as time) < '8:01' THEN '08:00'
WHEN cast(last_update_date as time) >= '8:01' AND cast(last_update_date as time)
< '16:31' THEN '16:30'
WHEN cast(last_update_date as time) >='16:31' and cast(last_update_date as time)
< '20:31' THEN '20:30'
END TimeInterval2
,
CASE WHEN
requisition_status_Description = 'Pending' THEN 'Active'
WHEN requisition_status_Description = 'Created' THEN 'Active'
WHEN requisition_status_Description = 'Requested' THEN 'Active'
WHEN requisition_status_Description = 'Approved' THEN 'Completed'
WHEN requisition_status_Description = 'Denied' THEN 'Completed'
WHEN requisition_status_Description = 'Cancelled' THEN 'Completed'
END RequisitionStatus
,
CASE WHEN
cast(last_update_date as time) < '16:30' then 'Regular'
WHEN cast(last_update_date as time) >= '16:30' then 'Extended Hours'
End ShiftTime, #StartWeek StartWeek, #EndWeek EndWeek
,*
FROM #DataSet

Related

Query with Sum( Case When )

I have a problem in using Sum( Case When ). When I use the below query:
SELECT CONVERT(VARCHAR(10), [datetime], 111) as [Date],
Installation_Id,
Installation_Name,
Round (ISNULL (sum (case when ((cast([datetime] as time) >= '07:00:00' and cast([datetime] as time) < '09:00:00') or (cast([datetime] as time) >= '16:00:00' and cast([datetime] as time) < '20:00:00') and (Installation_ID = '18374' or Installation_ID = '18466' or Installation_ID = '18375' or Installation_ID = '18372' )) then availability/240
when ((cast([datetime] as time) >= '07:00:00' and cast([datetime] as time) < '09:00:00') or (cast([datetime] as time) >= '16:00:00' and cast([datetime] as time) < '20:00:00') and (Installation_ID = '18373')) then availability/216
when ((cast([datetime] as time) >= '07:00:00' and cast([datetime] as time) < '09:00:00') or (cast([datetime] as time) >= '16:00:00' and cast([datetime] as time) < '20:00:00') and (Installation_ID = '18467' )) then availability/48 end),0),4) as [Availability from 7am to 9am or 4pm to 8pm]
from Reserve_Power
where Installation_Id = 18467
Group by CONVERT(VARCHAR(10), [datetime], 111),Installation_Id,Installation_Name
The result that I get is :
Availabilty = 0.7736
But when I run the below query:
SELECT CONVERT(VARCHAR(10), [datetime], 111) as [Date],
Installation_Id,
Installation_Name,
sum (case when ((cast([datetime] as time) >= '07:00:00' and cast([datetime] as time) < '09:00:00') or (cast([datetime] as time) >= '16:00:00' and cast([datetime] as time) < '20:00:00') and (Installation_ID = '18467' )) then availability/48 end) as [Availability from 7am to 9am or 4pm to 8pm]
from Reserve_Power
where Installation_Id = 18467 and CONVERT(VARCHAR(10), [datetime], 111) = '2023-01-22'
Group by CONVERT(VARCHAR(10), [datetime], 111),Installation_Id,Installation_Name;
The result that I get is:
Availability = 1
The result from second query is correct, so I assume there is a problem in the part related to Sum() function.
Can you help me with this issue? Thanks!
I solved the problem. I just explain it maybe someone has something similar in future. The problem was in OR clause and there were missing parentheses. When I used parentheses for OR clause, it was solved.
SELECT CONVERT(date, [datetime]) as [Date],
Installation_Id,
Installation_Name,
Round (ISNULL (sum (case when (cast([datetime] as time) >= '06:00:00' and cast([datetime] as time) < '22:00:00' and (Installation_ID = '18374' or Installation_ID = '18466' or Installation_ID = '18375' or Installation_ID = '18372' )) then availability/640
when (cast([datetime] as time) >= '06:00:00' and cast([datetime] as time) < '22:00:00' and (Installation_ID = '18373')) then availability/576
when (cast([datetime] as time) >= '06:00:00' and cast([datetime] as time) < '22:00:00' and (Installation_ID = '18467')) then availability/128 end),0),4) as [Availability in critical hours 6am to 10pm],
Round (ISNULL (sum (case when (((cast([datetime] as time) >= '07:00:00' and cast([datetime] as time) < '09:00:00') or (cast([datetime] as time) >= '16:00:00' and cast([datetime] as time) < '20:00:00')) and (Installation_ID = '18374' or Installation_ID = '18466' or Installation_ID = '18375' or Installation_ID = '18372' )) then availability/240
when (((cast([datetime] as time) >= '07:00:00' and cast([datetime] as time) < '09:00:00') or (cast([datetime] as time) >= '16:00:00' and cast([datetime] as time) < '20:00:00')) and (Installation_ID = '18373')) then availability/216
when (((cast([datetime] as time) >= '07:00:00' and cast([datetime] as time) < '09:00:00') or (cast([datetime] as time) >= '16:00:00' and cast([datetime] as time) < '20:00:00')) and (Installation_ID = '18467' )) then availability/48 end),0),4) as [Availability in critical hours 7am to 9am or 4pm to 8pm]
from Reserve_Power
where Installation_Id = 18373
Group by CONVERT(date, [datetime]),Installation_Id,Installation_Name

Hourly and daily groups with overlapping days (11:00 pm-1:00am)

I'm attempting to count number of ids active during a given hourly window and day. I have three columns: start_time, end_time, and id.
Most of the groups are standard same-day groupings, i.e., 9am-11am, 11am-1pm, etc.
One of the groupings overlaps two days (11pm-1am). That is, May 16 11:01 PM and May 17 12:01 AM should be in the same group. But when composing a simple query, you'd end up grouping May 17 12:01 AM within the May 17 11:00pm.
I've tried several queries with several variations of case statements and subqueries, but can't get the gist.
This below query attempt gives me 0 for 11pm_1am column. I figured I could just move a 12:30 AM time into the previous date and count it there, but no luck.
select date_trunc('day', start_time_1) as date_active
, count(distinct(case when CAST(start_time_1 AS TIME) <= '06:00:00' and CAST(end_time_1 AS TIME) >= '01:00:00' then id end)) as early_morning
, count(distinct(case when CAST(start_time_1 AS TIME) <= '00:00:00' and CAST(end_time_1 AS TIME) >= '23:00:00' then id end)) as overnight_11pm_1am
from
(select id
, case
when cast(start_time as time) between '00:00:00' and '01:00:00'
then start_time - INTERVAL '01:00' HOUR TO MINUTE
else start_time
end as start_time_1
,case
when cast(end_timeas time) between '00:00:00' and '01:00:00'
then end_time - INTERVAL '01:00' HOUR TO MINUTE
else end_time
end as end_time_1
from table
where start_time >= '2021-01-01'
and start_time < '2021-01-04'
)
group by date_active
Out of ideas.

Count values in time ranges (SQL)

I am trying to make a sql query in which I want to count the people comprised in three ranges:
Tomorrow (from 06:00 a.m. to 12:00 p.m.)
Afternoon (from 12:00 p.m. to 9:00 p.m.)
Night (from 9:00 p.m. to 6:00 a.m.)
I have two attributes, check in time and check out time which have the following format:
2020-05-20 12:10:29.000
I am doing it in the following way but it does not work, for example, in the night:
select (case when datepart(hour, dateIn) > datepart(hour, '21')) and
datepart(minute, dateIn) > datepart(minute, '00'))
If I understand correctly, you can subtract 6 hours to get the date and then use time comparisons for the shift. So, I think you want:
select convert(date, dateadd(hour, -6, t.datein)), v.shift, count(*)
from t cross apply
(values (case when convert(time, t.datein) < '06:00:00' then 'night'
when convert(time, t.datein) < '12:00:00' then 'morning'
when convert(time, t.datein) < '21:00:00' then 'afternoon'
else 'night'
end)
) v(shift)
group by convert(date, dateadd(hour, -6, datein)), v.shift;

SQL DateDiff in Minutes Spanning Over Night

Trying to get the difference in minutes between a datetime field and a time field. I'm using the datediff function.
When the start time starts on one date like '2018-01-08 22:35:55.043' and the end time is the following day like '00:35:56.2136644', the result is counting from the end time to the start time.
Examples:
select DATEDIFF(MINUTE, CAST('2018-01-08 22:35:55.043' AS TIME), '00:35:56.2136644') AS minDiff1
select DATEDIFF(MINUTE, '00:35:56.2136644', CAST('2018-01-08 22:35:55.043' AS TIME)) AS minDiff2
select DATEDIFF(MINUTE, CONVERT(TIME, '2018-01-08 22:35:55.043'), '00:35:56.2136644') AS minDiff3
select DATEDIFF(MINUTE, '00:35:56.2136644', CONVERT(TIME, '2018-01-08 22:35:55.043')) AS minDiff4
The results were different from what I was expecting. The desired result would be 120 minutes.
minDiff1 = -1320
minDiff2 = 1320
minDiff3 = -1320
minDiff4 = 1320
Original Query
select DATEDIFF(MINUTE, CAST(test_start_datetime as TIME), test_end_time) AS minDiff
from user_exam
The following assumes that the time belongs to the same day or the very next day:
SELECT *, CASE
-- same day -- start time is less than end time
WHEN CAST(datetimecol AS time) <= timecol THEN DATEDIFF(MINUTE, CAST(datetimecol AS time), timecol)
-- next day -- start time is more than end time (it rolled over into next day)
ELSE 1440 - DATEDIFF(MINUTE, timecol, CAST(datetimecol AS time))
END
FROM (VALUES
(CAST('2018-01-08 22:35:55.043' AS DATETIME), CAST('22:35:55.0433333' AS TIME)),
(CAST('2018-01-08 22:35:55.043' AS DATETIME), CAST('23:35:56.2136644' AS TIME)),
(CAST('2018-01-08 22:35:55.043' AS DATETIME), CAST('00:35:56.2136644' AS TIME))
) AS tests(datetimecol, timecol)
In the above example 1440 is the number of minutes in 24 hours.
Demo on DB Fiddle
Let us first reconsider your examples:
select DATEDIFF(MINUTE, CAST('2018-01-08 22:35:55.043' AS TIME), '00:35:56.2136644') AS minDiff1
select DATEDIFF(MINUTE, '00:35:56.2136644', CAST('2018-01-08 22:35:55.043' AS TIME)) AS minDiff2
select DATEDIFF(MINUTE, CONVERT(TIME, '2018-01-08 22:35:55.043'), '00:35:56.2136644') AS minDiff3
select DATEDIFF(MINUTE, '00:35:56.2136644', CONVERT(TIME, '2018-01-08 22:35:55.043')) AS minDiff4
Converting/casting from datetime to time throws the date part away. Thus, you are actually running:
select DATEDIFF(MINUTE, '22:35:55.043'', '00:35:56.2136644') AS minDiff1
select DATEDIFF(MINUTE, '00:35:56.2136644', '22:35:55.043') AS minDiff2
select DATEDIFF(MINUTE, '22:35:55.043', '00:35:56.2136644') AS minDiff3
select DATEDIFF(MINUTE, '00:35:56.2136644'22:35:55.043') AS minDiff4
At this point, you seem to not be considering the fact that DATEDIFF is directed, meaning it counts (first argument units passed) FROM second argument TO third argument. Thus, since 00:35 is 1320 minutes earlier than 22:35 (of the same day), 00:35 -> 22:35 returns 1320, whereas 22:35 -> 00:35 returns -1320.
To be completely precise, since DATEDIFF uses datetimes, your times/time-representing strings are implicitly converted to dates. Since a date is not provided by you, the date used is the one with value 0: 1st January 1900. That's the common day the function acts upon.
If you want to see 120 that's mean time difference is not enough for your purpose. With your question you want to find difference between 22:35 and following day 00:35
You need to find DATETIME difference something like that:
SELECT DATEDIFF(MINUTE, CAST(GETDATE() AS DATETIME)
+CAST(CAST('22:35:55.2136644' AS TIME) AS DATETIME)
,
CAST(GETDATE() AS DATETIME)+1
+CAST(CAST('00:35:56.2136644' AS TIME)AS DATETIME)
) AS minDiff1

compare the average purchase_amount between two time ranges

The question is as follows:
How high was the average purchase amount in the morning (05-11) compared to (17-23) in the evening?
I don't know how to compare them.
I tried this but I only get one big amount.
select avg(purchase_amount)
from case_data_order
where cast (create_timestamp as time ) between '05:00:00' and '11:00:00'
or cast(create_timestamp as time) between '17:00:00' and '23:00:00';
I use Postgres 9.6
try going with FILTER predicate, like this:
SELECT
count(*) AS unfiltered,
count(*) FILTER (WHERE i < 5) AS filtered
FROM generate_series(1,10) AS s(i);
unfiltered | filtered
------------+----------
10 | 4
(1 row)
so in your case it would be something like
select
avg(purchase_amount) FILTER (where cast (create_timestamp as time ) between '05:00:00' and '11:00:00') as morning
, avg(purchase_amount) FILTER (where cast (create_timestamp as time ) between '17:00:00' and '23:00:00') as evening
from case_data_order
How to get the averages:
select d,
avg(case when t between '05:00:00' and '11:00:00' then purchase_amount end) as am,
avg(case when t between '17:00:00' and '23:00:00' then purchase_amount end) as pm
from
(
select purchase_amount,
cast(create_timestamp as time) as t,
cast(create_timestamp as date) as d
from case_data_order
) dt
group by d
smth like could help:
SELECT
AVG(purchase_amount),
CASE
WHEN CAST(create_timestamp AS TIME) BETWEEN '05:00:00' AND '11:00:00'
THEN 'day'
WHEN CAST(create_timestamp AS TIME) BETWEEN '17:00:00' AND '23:00:00'
THEN 'night'
END gr
FROM case_data_order
WHERE CAST(create_timestamp AS TIME) BETWEEN '05:00:00' AND '11:00:00'
OR CAST(create_timestamp AS TIME) BETWEEN '17:00:00' AND '23:00:00'
GROUP BY
CASE
WHEN CAST(create_timestamp AS TIME) BETWEEN '05:00:00' AND '11:00:00'
THEN 'day'
WHEN CAST(create_timestamp AS TIME) BETWEEN '17:00:00' AND '23:00:00'
THEN 'night'
END gr;