Query with Sum( Case When ) - sql

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

Related

Query to find extract time between

Im a beginner with SQL and need help to get some transactions in our WMS between 00.00.00 and 06.00.00 but can't make it work.
This is how far I have come,
SELECT cast(datreg as time) [time], logguser, l16lcode, partno, l16qty, datreg
FROM L16T3
WHERE datreg > '0000-00-00 00:00:00'
AND datreg < '9999-99-99 06:00:00'
AND L16T3.l16lcode = 2
I dont know what to write to get transactions only between 24.00-06.00
(Using SQL Server 2012)
Best Regards
Try this condition:
WHERE DATEPART(hour, datreg) BETWEEN 0 AND 5 OR
(DATEPART(hour, datreg) = 6 AND DATEPART(minute, datreg) = 0 AND DATEPART(second, datreg) = 0)
I would suggest:
SELECT cast(datreg as time) as [time], logguser, l16lcode, partno, l16qty, datreg
FROM L16T3 l
WHERE CONVERT(time, l.datreg) >= '00:00:00' AND
CONVERT(time, l.datreg) < '06:00:00' AND
l.l16lcode = 2;
You can also use the hours:
WHERE DATEPART(hour, l.datreg) >= 0 AND
DATEPART(hour, l.datreg) < 6 AND
l.l16lcode = 2;
However, this does not generalize so easily if, say, the second time were 06:30:00.
Something lie this perhaps:
SELECT IIF(CONVERT(TIME, GETDATE()) BETWEEN '00:00:00' AND '23:59:59','TRUE','FALSE');
Try the above query in SQLFiddle
In your case it would be something like this:
SELECT cast(datreg as time) [time], logguser, l16lcode, partno, l16qty, datreg
FROM L16T3
WHERE CONVERT(TIME, datreg ) BETWEEN '00:00:00' AND '06:00:00'
AND L16T3.l16lcode = 2

Move code to nested query to resolve copypaste

I have sql query
Here is code
SELECT tt.creationdate AS CreatedDate,
DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) AS DaysOpen,
CASE WHEN DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) >= 180 THEN '180+ Days'
WHEN DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) >= 150 THEN '150 - 180 Days'
WHEN DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) >= 120 THEN '120 - 150 Days'
WHEN DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) >= 90 THEN '90 - 120 Days'
WHEN DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) >= 60 THEN '60 - 90 Days'
WHEN DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) >= 30 THEN '30 - 60 Days'
WHEN DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) >= 0 THEN '0 - 30 Days'
ELSE NULL END AS TaskAging,
tms.SupportType,
tms.SupportModule,
tt.*
FROM public.tasks tt
LEFT JOIN
public.tasks_meta_support tms
ON tms.taskid = tt.Id
WHERE tt.issupportticket = 1
AND tt.supportorganizationid = 65277
AND tt.completeddate IS NULL
AND tt.isdeleted = 0
I need to move DaysOpen to nested query to reuse it in CASE
How I can do this correctly?
Just use a subquery:
SELECT tt.DaysOpen,
(CASE WHEN tt.DaysOpen >= 180 THEN '180+ Days'
WHEN tt.DaysOpen >= 150 THEN '150 - 180 Days'
WHEN tt.DaysOpen >= 120 THEN '120 - 150 Days'
WHEN tt.DaysOpen >= 90 THEN '90 - 120 Days'
WHEN tt.DaysOpen >= 60 THEN '60 - 90 Days'
WHEN tt.DaysOpen >= 30 THEN '30 - 60 Days'
WHEN tt.DaysOpen >= 0 THEN '0 - 30 Days'
END )AS TaskAging,
tms.SupportType,
tms.SupportModule,
tt.*
FROM (SELECT tt.*, DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) AS DaysOpen
FROM public.tasks tt
) tt LEFT JOIN
public.tasks_meta_support tms
ON tms.taskid = tt.Id
WHERE tt.issupportticket = 1
AND tt.supportorganizationid = 65277
AND tt.completeddate IS NULL
AND tt.isdeleted = 0;
Note that the ELSE is redundant, so I removed it.
First I would move the GETDATE() to #Now and set it just before the query. You might get a difference in behaviour if this run 23:59:59.999, but in general you want the values fromwhen you asked, not when it's running.
Also try not to use wildcards when selecting columns.
Also, do you want all rows from public.tasks and only the matching one from publi.tasks_meta_support or all rows from public.tasksmeta_support? The order you write thing is really important here (https://learn.microsoft.com/en-us/previous-versions/sql/sql-server-2005/ms177634(v%3dsql.90)#e-using-the-sql-92-left-outer-join-syntax).
That said you could use a CTE or some a subquery.
I would go with a CTE and writing out all the columns.
Not knowing which columns there are in public.tasks maybe this subquery?
Note that I moved everything related to public.tasks to tt.
DECLARE #Now datetime;
SET #Now = #Now;
SELECT ptsq.CreatedDate,
ptsq.DaysOpen,
ptsq.TaskAging,
tms.SupportType,
tms.SupportModule,
ptsq.*
FROM (SELECT creationdate AS CreatedDate,
DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) AS DaysOpen,
CASE WHEN DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) >= 180 THEN '180+ Days'
WHEN DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) >= 150 THEN '150 - 180 Days'
WHEN DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) >= 120 THEN '120 - 150 Days'
WHEN DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) >= 90 THEN '90 - 120 Days'
WHEN DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) >= 60 THEN '60 - 90 Days'
WHEN DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) >= 30 THEN '30 - 60 Days'
WHEN DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) >= 0 THEN '0 - 30 Days'
FROM public.tasks
WHERE issupportticket = 1
AND supportorganizationid = 65277
AND isdeleted = 0) ptsq
LEFT OUTER JOIN public.tasks_meta_support tms ON ptsq.taskid = tms.Id -- Assuming you want all rows from public.tasks.
WHERE ptsq.completeddate IS NULL -- Could probably be moved to ptsq

Display Records Up to a Certain Time Period Only

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

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;

How to Unite Same PostgreSQL Data

I have a postgresql statement which is:
( select cast(start_time as date) as time , SUM(count) as count
from tbl_product
where ( cast(start_time as date) >= '2016-08-30 23:00:00' and cast(start_time as date) <= '2016-09-01 20:00:00' )
and ( extract(hour from start_time) >= 23 and extract(hour from start_time) <= 24)
group by time order by time limit 5 )
UNION ( select cast(start_time as date) as time , SUM(count) as count
from tbl_product
where ( cast(start_time as date) >= '2016-08-31 23:00:00' and cast(start_time as date) <= '2016-09-01 20:00:00' )
and ( extract(hour from start_time) >= 0 and extract(hour from start_time) < 20)
group by time order by time limit 5 )
But it returns the same data for the same date, because of a UNION statement
time count
date numeric
"2016-08-31" 543595
"2016-08-31" 3666277
"2016-09-01" 3365093
How can I add these data values like:
time count
date numeric
"2016-08-31" 4209872
"2016-09-01" 3365093
Thanks for helping.
You need to move the GROUP BY out of the individual queries. Something like that:
SELECT time, SUM(count) as count FROM (
( select cast(start_time as date) as time , count
from tbl_product
where ( cast(start_time as date) >= '2016-08-30 23:00:00' and cast(start_time as date) <= '2016-09-01 20:00:00' )
and (extract(hour from start_time) >= 23))
UNION ALL
( select cast(start_time as date) as time , count
from tbl_product
where ( cast(start_time as date) >= '2016-08-31 23:00:00' and cast(start_time as date) <= '2016-09-01 20:00:00' )
and ( extract(hour from start_time) >= 0 and extract(hour from start_time) < 20))
) AS t
GROUP BY time ORDER by time;
I've also changed the UNION to a UNION ALL, because it seems to make more sense in this case. Finally, the test extract(hour from start_time) <= 24 is always true, so it's redundant.
try this query:
select
exe.time_,
sum(exe.count_)
from
(
select cast(start_time as date) as time_ , SUM(count) as count_
from tbl_product
where ( cast(start_time as date) >= '2016-08-30 23:00:00' and cast(start_time as date) <= '2016-09-01 20:00:00' )
and ( extract(hour from start_time) >= 23 and extract(hour from start_time) <= 24)
group by time order by time limit 5
UNION
select cast(start_time as date) as time_, SUM(count) as count_
from tbl_product
where ( cast(start_time as date) >= '2016-08-31 23:00:00' and cast(start_time as date) <= '2016-09-01 20:00:00' )
and ( extract(hour from start_time) >= 0 and extract(hour from start_time) < 20)
group by time order by time limit 5
) exe
group by exe.time_