Calculating columns vertically - sql

We are trying to do an analysis of how long our staff have been working on a hourly basis for trending and forecasting purposes.
I want to do a headcount by calculating all the values in the columns vertically.
This is the outputs in SQL in hourly format
(I have circled the values I want to sum up)
As long as the value is more than 0, I want to count it as 1 as this is for headcount by hour.
This is part of my query to produce the output.
SELECT
--b.*,
b.EMPLOYEENAME,
B.DEPARTMENT,
CONVERT(datetime, LEFT(b.SHIFTA_start,17),103) AS SHIFTA_start,
CONVERT(datetime, LEFT(b.ShiftA_End,17),103) as ShiftA_End,
b.StartTime_HOUR,
b.StartTime_min,
b.EndTime_HOUR,
b.EndTime_min,
CASE WHEN b.[0H_START] < b.[0H_END] THEN b.[0H_START] ELSE b.[0H_END] END AS [0],
CASE WHEN b.[1H_START] < b.[1H_END] THEN b.[1H_START] ELSE b.[1H_END] END AS [1]
from
(
/*Step 2 - calculating minutes from starttime and endtime */
select a.*,
/**Calculating the number of minutes worked from start_time MIN **/
CASE WHEN a.StartTime_HOUR = 0 and a.[0] = 1 AND a.StartTime_min !=0 THEN cast(cast((60-a.StartTime_min) as decimal(10,2))/60 as decimal(10,2)) ELSE a.[0] END AS [0H_START],
CASE WHEN a.StartTime_HOUR = 1 and a.[1] = 1 AND a.StartTime_min !=0 THEN cast(cast((60-a.StartTime_min) as decimal(10,2))/60 as decimal(10,2)) ELSE a.[1] END AS [1H_START],
/**Calculating the number of minutes worked from END_time MIN **/
CASE WHEN a.EndTime_HOUR = 0 and a.[0] = 1 AND a.EndTime_min !=0 THEN cast(cast((a.EndTime_min) as decimal(10,2))/60 as decimal(10,2)) ELSE a.[0] END AS [0H_END],
CASE WHEN a.EndTime_HOUR = 1 and a.[1] = 1 AND a.EndTime_min !=0 THEN cast(cast((a.EndTime_min) as decimal(10,2))/60 as decimal(10,2)) ELSE a.[1] END AS [1H_END]
from
(--Step 1:
/*to determine 1 or 0 using the start and end hour
If time falls in the respective hour = 1
if time doesnt fall in the respective hours = 0*/
SELECT
[EMPLOYEENAME],
[DEPARTMENT],
[SHIFTA_start],
CASE WHEN [SHIFTA_START] !='' OR SHIFTA_START != NULL THEN CONVERT(datetime, LEFT([SHIFTA_START],17),103) ELSE NULL END AS SHIFTA_START_con,
CASE WHEN [SHIFTA_START] !='' OR SHIFTA_START != NULL THEN DATEPART(hh,CONVERT(datetime, LEFT([SHIFTA_START],17),103)) ELSE NULL END AS StartTime_HOUR,
CASE WHEN [SHIFTA_START] !='' OR SHIFTA_START != NULL THEN DATEPART(mi,CONVERT(datetime, LEFT([SHIFTA_START],17),103)) ELSE NULL END AS StartTime_min,
[SHIFTA_end],
CASE WHEN [SHIFTA_END] !='' OR SHIFTA_end != NULL THEN CONVERT(datetime, LEFT([SHIFTA_END],17),103) ELSE NULL END AS SHIFTA_END_con,
CASE WHEN [SHIFTA_END] !='' OR SHIFTA_end != NULL THEN DATEPART(hh,CONVERT(datetime, LEFT([SHIFTA_end],17),103)) ELSE NULL END AS EndTime_HOUR,
CASE WHEN [SHIFTA_END] !='' OR SHIFTA_end != NULL THEN DATEPART(mi,CONVERT(datetime, LEFT([SHIFTA_end],17),103)) ELSE NULL END AS EndTime_min,
CASE WHEN [SHIFTA_START] !='' AND 0 BETWEEN DATEPART(hh,CONVERT(datetime, LEFT([SHIFTA_START],17),103)) AND DATEPART (hh,CONVERT(datetime, LEFT([SHIFTA_end],17),103)) THEN 1 ELSE 0 END AS [0],
CASE WHEN [SHIFTA_START] !='' AND 1 BETWEEN DATEPART(hh,CONVERT(datetime, LEFT([SHIFTA_START],17),103)) AND DATEPART (hh,CONVERT(datetime, LEFT([SHIFTA_end],17),103)) THEN 1 ELSE 0 END AS [1]
from [DatabaseTable].[dbo].[ATTENDANCE]
where ShiftA_Start != '' and ShiftA_End !='' and shiftA_start != shiftA_End
)a
)b
Please help, thank you v much!

If you want to calculate the number of all values in this column you can go simply with:
SELECT COUNT(T.[22]) FROM Table AS T
WHERE T.[22] > 0

Related

Conditional Where when using Group By

I have a working procedure to show the report for given range of period.
The below proc finds all the bookings for the given period of time and shows for each month group
CREATE PROCEDURE [dbo].[GetSummaryOverviewReport] (
#StartDate SMALLDATETIME = NULL
,#EndDate SMALLDATETIME = NULL
,#IncludeVAT BIT = 0
,#AddedAfter SMALLDATETIME
,#HasObservation BIT = 0
,#IncludeCancelledBooking BIT = 0
)
AS
BEGIN
SET NOCOUNT ON
BEGIN
SELECT YEAR(StartTime) [Year]
,MONTH(StartTime) [Month]
,COUNT(BookingId) [BookingCount]
,SUM(CASE
WHEN IsVAT = 1
AND #IncludeVAT = 1
THEN (Price / 100) * 80
ELSE Price
END) AS TotalPrice
,PaidCount = sum(CASE
WHEN B.PaymentStatus = 'FullyPaid'
THEN 1
ELSE 0
END)
,PaidSum = sum(CASE
WHEN B.PaymentStatus = 'FullyPaid'
THEN (
CASE
WHEN IsVAT = 1
AND #IncludeVAT = 1
THEN (Price / 100) * 80
ELSE Price
END
)
ELSE 0
END)
,C.CategoryId
,CategoryName
FROM Category c
LEFT JOIN Booking B ON C.CategoryId = B.CategoryId
WHERE B.AddedDateTime > #AddedAfter
AND ISNULL(B.IsCancelled, 0) = 0
AND (
(
B.StartTime BETWEEN #StartDate
AND #EndDate
)
OR (
B.StartTime BETWEEN #StartDate
AND #EndDate
)
)
AND (
#HasObservation = 0
OR B.PatientID IN (
SELECT PatientID
FROM PatientXObservation O
WHERE ObservationId IN (
1
,2
,4
)
)
)
GROUP BY YEAR(StartTime)
,MONTH(StartTime)
,C.CategoryId
,CategoryName
ORDER BY 1
,2
,CategoryName
END
END
Now we want to add a filter #IncludeCancelledBooking parameter. So user can select whether to show cancelled bookings or not. As of now the procedure ignores the cancelled booking and shows only non cancelled booking..
I couldn't able to find out how to add this condition while grouping the records. I need to use AND ISNULL(B.IsCancelled, 0) = 0 based on #IncludeCancelledBooking
Is this the logic that you want?
(#IncludeCancelled <> 'Y' OR Booking ISNULL(B.IsCancelled, 0) = 0)
If IsCancelled is also a BIT(like #IncludeCancelled), then you could use:
AND ISNULL(B.IsCancelled, 0) IN (0, #IncludeCancelled)
If #IncludeCancelled is 0, then this is effectively the same logic you have now (i.e. = 0). If #IncludeCancelled is 1, then this includes where IsCancelled = 1.
Assuming you are passing value 1 for the variable #IncludeCancelled for including the cancelled booking. Then change the WHERE condition like below.
AND ISNULL(B.IsCancelled,0)=
CASE WHEN #IncludeCancelled=1
THEN ISNULL(B.IsCancelled,0)
ELSE 0 END

Update multiple variables in a single query

I have a table with Sum of Amounts for Each Weekday (Sunday to Saturday) . Table structure is as below.
I need to assign these table values into parameters. For E.g : I need to assign sum of rdate '2015-11-15' i.e 324 to a variable #sundayval , 374 to variable #mondayval etc...
How to do this In a single update query. I have tried out with Case statement,
But it only assigns value to variable #saturdayval .
Thanks for the Help.
This does the job. It doesn't depend on any particulat DATEFIRST settings - it instead uses an arbitrarily chosen sunday (I picked 17th May this year) (what I usually refer to as a "known good" date because it has the property we're looking for, in this case the right day of the week):
declare #t table ([sum] int not null,rdate datetime2 not null)
insert into #t([sum],rdate) values
(324,'20151115'),
(374,'20151116'),
(424,'20151117'),
(474,'20151118'),
(524,'20151119'),
(574,'20151120'),
(624,'20151121')
declare #sundayval int
declare #mondayval int
declare #tuesdayval int
declare #wednesdayval int
declare #thursdayval int
declare #fridayval int
declare #saturdayval int
select
#sundayval = SUM(CASE WHEN DATEPART(weekday,rdate) = DATEPART(weekday,'20150517') THEN [sum] END),
#mondayval = SUM(CASE WHEN DATEPART(weekday,rdate) = DATEPART(weekday,'20150518') THEN [sum] END),
#tuesdayval = SUM(CASE WHEN DATEPART(weekday,rdate) = DATEPART(weekday,'20150519') THEN [sum] END),
#wednesdayval = SUM(CASE WHEN DATEPART(weekday,rdate) = DATEPART(weekday,'20150520') THEN [sum] END),
#thursdayval = SUM(CASE WHEN DATEPART(weekday,rdate) = DATEPART(weekday,'20150521') THEN [sum] END),
#fridayval = SUM(CASE WHEN DATEPART(weekday,rdate) = DATEPART(weekday,'20150522') THEN [sum] END),
#saturdayval = SUM(CASE WHEN DATEPART(weekday,rdate) = DATEPART(weekday,'20150523') THEN [sum] END)
from #t
select #sundayval,#mondayval,#tuesdayval,#wednesdayval,#thursdayval,#fridayval,#saturdayval
Result:
----------- ----------- ----------- ----------- ----------- ----------- -----------
324 374 424 474 524 574 624
Ok - let's do it this way: the else case is set to return itself, so each variable essentially aggregates as a coalesce. Note: I don't have any way to test this right now. :)
SELECT
#sundayval = case when DATEPART(weekday, rdate) = 1 then sum else #sundayval end
, #mondayval = case when DATEPART(weekday, rdate) = 2 then sum else #mondayval end
, #tuesdayval = case when DATEPART(weekday, rdate) = 3 then sum else #tuesdayval end
, #wednesdayval = case when DATEPART(weekday, rdate) = 4 then sum else #wednesdayval end
, #thursdayval = case when DATEPART(weekday, rdate) = 5 then sum else #thursdayval end
, #fridayval = case when DATEPART(weekday, rdate) = 6 then sum else #fridayval end
, #saturdayval = case when DATEPART(weekday, rdate) = 7 then sum else #saturdayval end
FROM TABLE
I have No idea Whether a Single UPDATE Statement will do this. I have assigned value for Each Variable like as Below,
SELECT #SunTotal = [sum]
FROM [table]
where rdate = #Startdate
SELECT #MonTotal = [sum]
FROM [table]
where rdate = DATEADD(DAY,1,#Startdate)
SO ON...

Sorting data by YEAR

I am completely new to SQL and have really only run statements with minimal modifications. I am currently trying to modify this specific query:
SELECT DISTINCT (ROUND (windspeed * 2, -1) / 2) AS wndspd,
SUM (CASE WHEN month = 1 THEN 1 ELSE NULL END) AS January,
SUM (CASE WHEN month = 2 THEN 1 ELSE NULL END) AS February,
SUM (CASE WHEN month = 3 THEN 1 ELSE NULL END) AS March,
SUM (CASE WHEN month = 4 THEN 1 ELSE NULL END) AS April,
SUM (CASE WHEN month = 5 THEN 1 ELSE NULL END) AS May,
SUM (CASE WHEN month = 6 THEN 1 ELSE NULL END) AS June,
SUM (CASE WHEN month = 7 THEN 1 ELSE NULL END) AS July,
SUM (CASE WHEN month = 8 THEN 1 ELSE NULL END) AS August,
SUM (CASE WHEN month = 9 THEN 1 ELSE NULL END) AS September,
SUM (CASE WHEN month = 10 THEN 1 ELSE NULL END) AS October,
SUM (CASE WHEN month = 11 THEN 1 ELSE NULL END) AS November,
SUM (CASE WHEN month = 12 THEN 1 ELSE NULL END) AS December
FROM table1
WHERE platformid = 'coollocation'
AND networktype = 'typeofcoollocation'
AND (windspeedqc <> '2' OR windspeedqc IS NULL)
GROUP BY ROUND (windspeed * 2, -1) / 2
ORDER BY ROUND (windspeed * 2, -1) / 2;
What I want from the query is to instead of sorting by months, sort by all the years that are available for the specific location (platformid). So far I have just modified the script so that it looks like this:
SELECT DISTINCT
(ROUND (windspeed * 2, -1) / 2) AS wndspd,
SUM (
CASE
WHEN TO_CHAR (observationtime, 'YYYY') = 1957 THEN 1
ELSE NULL
END)
AS given_year,
SUM (
CASE
WHEN TO_CHAR (observationtime, 'YYYY') = 1958 THEN 1
ELSE NULL
END)
AS GIVEN_YEAR2
FROM table1
WHERE platformid = 'coollocation'
AND networktype = 'typeofcoollocation'
AND (windspeedqc <> '2' OR windspeedqc IS NULL)
GROUP BY ROUND (windspeed * 2, -1) / 2
ORDER BY ROUND (windspeed * 2, -1) / 2;
The problem is that I know that the years go from 1957-2015. I'm pretty sure that there is a more efficient way to list out the information that I want without creating a specific SUM string for every single year. I have no idea how to do that however. Please help!
You can try creating a PIVOT query
SELECT wndspd, [1957], [1958], [1959],...etc....[2013], [2014], [2015] FROM
(
SELECT (ROUND (windspeed * 2, -1) / 2) AS wndspd,
YEAR(observationtime) yr
FROM table1
WHERE platformid = 'coollocation'
AND networktype = 'typeofcoollocation'
AND (windspeedqc <> '2' OR windspeedqc IS NULL)
) src
PIVOT (
COUNT(yr)
FOR yr IN ([1957],[1958], [1959],...etc....[2013], [2014], [2015])
) pvt
you'll have to fill in all of the other years between 1959 and 2013.
here's an easier way to create all of the columns from 1957 to the current year.
DECLARE #PivotCols VARCHAR(MAX),
#MinYear INT = 1957,
#CurYear INT = YEAR(GETDATE())
WHILE #MinYear < #CurYear
BEGIN
SET #PivotCols = COALESCE( #PivotCols + '],[', '[') + CONVERT(VARCHAR, #MinYear)
SET #MinYear = #MinYear + 1
END
SET #PivotCols = CONCAT(#PivotCols,'],[',CONVERT(VARCHAR, #MinYear),']')
DECLARE #Sql VARCHAR(MAX) = '
SELECT wndspd, ' + #PivotCols + ' FROM
(
SELECT (ROUND (windspeed * 2, -1) / 2) AS wndspd,
YEAR(observationtime) yr
FROM table1
WHERE platformid = ''coollocation''
AND networktype = ''typeofcoollocation''
AND (windspeedqc <> ''2'' OR windspeedqc IS NULL)
) src
PIVOT (
COUNT(yr)
FOR yr IN (' + #PivotCols + ')
) pvt
'
EXEC (#Sql)
I think you are essentially trying to do this:
SELECT DISTINCT (ROUND (windspeed * 2, -1) / 2) AS wndspd
,TO_CHAR(observationtime, 'YYYY') as year,
,COUNT(1) as occurrences
FROM table1
WHERE platformid = 'coollocation'
AND networktype = 'typeofcoollocation'
AND (windspeedqc <> '2' OR windspeedqc IS NULL)
GROUP BY (ROUND(windspeed * 2, -1) / 2), TO_CHAR(observationtime, 'YYYY')
ORDER BY 1, 2;
...however the count of occurrences in each year would then be represented by a row instead of a column.
Unfortunately there is no easy way to pivot the rows in this query into columns because you fundamentally need to know how many columns there are and ensure each row has the values populated properly.
At the end of the day you'll need to add a line for each year to your SELECT clause. It could look like this:
SELECT yearly.wndspd
,SUM(CASE WHEN yearly.year='1957' THEN yearly.occurrences ELSE 0 END) as 1957
,SUM(CASE WHEN yearly.year='1958' THEN yearly.occurrences ELSE 0 END) as 1958
...
,SUM(CASE WHEN yearly.year='2015' THEN yearly.occurrences ELSE 0 END) as 2015
FROM
(SELECT DISTINCT (ROUND (windspeed * 2, -1) / 2) AS wndspd
,TO_CHAR(observationtime, 'YYYY') as year,
,COUNT(1) as occurrences
FROM table1
WHERE platformid = 'coollocation'
AND networktype = 'typeofcoollocation'
AND (windspeedqc <> '2' OR windspeedqc IS NULL)
GROUP BY (ROUND(windspeed * 2, -1) / 2), TO_CHAR(observationtime, 'YYYY')) yearly
GROUP BY yearly.wndspd
ORDER BY 1, 2;

Join multiple queries with different search criteria

I have 4 queries that are identical with the exception of one of the criteria clauses at the end. I am trying to find a way to condense these 4 into 1, if possible. Currently, a program that we wrote calls these 4 statements through 4 stored procedures, but if I can make that 1 call that returns all 4, that would be great. Here's the bulk of the statement:
SELECT SUM(PausedTime) AS PausedMode
FROM UsageStats
WHERE StartDate >= CONVERT(VARCHAR(8), #StartDate, 112) AND StopDate < CONVERT(VARCHAR(8), #EndDate, 112)
AND LocationID = #LocationID
AND SystemID = #SystemID
AND PlayingArea = #PlayingArea
AND PausedTime > 0
I have 3 more of these and the only thing that changes is the field in the SUM calculation (all SUM fields are of type int):
SUM(PlayModeTime) AS PlayModeTime
SUM(RecordModeTime) AS RecordModeTime
SUM(ReplayModeTime) AS ReplayModeTime
and the last AND criteria
AND PlayModeTime > 0
AND RecordModeTime > 0
AND ReplayModeTime > 0
I tried using the CASE statement in the select clause but it failed:
SELECT
playMode = (CASE WHEN PlayModeTime > 0 THEN SUM(PlayModeTime) END),
pausedMode = (CASE WHEN PausedTime > 0 THEN SUM(PausedTime) END),
recordMode = (CASE WHEN RecordModeTime > 0 THEN SUM(RecordModeTime) END),
replayMode = (CASE WHEN ReplayModeTime > 0 THEN SUM(ReplayModeTime) END)
FROM UsageStats
WHERE StartDate >= CONVERT(VARCHAR(8), #StartDate, 112) AND StopDate < CONVERT(VARCHAR(8), #EndDate, 112)
AND LocationID = #LocationID
AND SystemID = #SystemID
AND PlayingArea = #PlayingArea
GROUP BY PlayModeTime, PausedTime, RecordModeTime, ReplayModeTime
I'd like to get something like this:
PlayModeTime | PausedMode | RecordModeTime | ReplayModeTime
---------------------------------------------------------------
200 340 10 55
Any help is appreciated.
I don't see why you need those conditions at all, since SUM will add zero when the value is 0. Can't you just SUM all of your columns?:
SELECT
playMode = SUM(PlayModeTime),
pausedMode = SUM(PausedTime),
recordMode = SUM(RecordModeTime),
replayMode = SUM(ReplayModeTime)
FROM UsageStats
WHERE StartDate >= CONVERT(VARCHAR(8), #StartDate, 112)
AND StopDate < CONVERT(VARCHAR(8), #EndDate, 112)
AND LocationID = #LocationID
AND SystemID = #SystemID
AND PlayingArea = #PlayingArea
You need to move the sum outside of the case statement:
SELECT
playMode = SUM(CASE WHEN PlayModeTime > 0 THEN PlayModeTime ELSE 0 END),
pausedMode = SUM(CASE WHEN PausedTime > 0 THEN PausedTime ELSE 0 END),
recordMode = SUM(CASE WHEN RecordModeTime > 0 THEN RecordModeTime ELSE 0 END),
replayMode = SUM(CASE WHEN ReplayModeTime > 0 THEN ReplayModeTime ELSE 0 END)
FROM UsageStats
WHERE StartDate >= CONVERT(VARCHAR(8), #StartDate, 112) AND StopDate < CONVERT(VARCHAR(8), #EndDate, 112)
AND LocationID = #LocationID
AND SystemID = #SystemID
AND PlayingArea = #PlayingArea
GROUP BY PlayModeTime, PausedTime, RecordModeTime, ReplayModeTime
The reason is that the case will be evaluated for each row. In your example, you're taking the sum of the column, but only for that row.
This only differs from Lamak's answer above in that it will treat negative values as zeroes in the sum.

error in sql query

I have this query:
( SELECT
SUM(
CONVERT(
FLOAT,
CASE '01'
WHEN '01' THEN
CASE SIGN((sltr_tran_amt - ISNULL(sltr_matched_amt, 0)))
WHEN 1 THEN
CASE DBO.glas_aging_oth(CONVERT(DATETIME, '2009/04/04') - FLOOR(sltr_pstng_date))
WHEN 0 THEN (sltr_tran_amt - ISNULL(sltr_matched_amt, 0))
ELSE 0
END
ELSE 0
END
WHEN '02' THEN
CASE SIGN((sltr_tran_amt - ISNULL(sltr_matched_amt, 0)))
WHEN -1 THEN
CASE DBO.glas_aging_oth(CONVERT(DATETIME, '2009/04/04') - FLOOR(sltr_doc_date))
WHEN 0 THEN (sltr_tran_amt - ISNULL(sltr_matched_amt, 0))
ELSE 0
END
ELSE 0
END
END
)
)
FROM
WHERE
CASE '01'
WHEN '01' THEN sltr_pstng_date
ELSE sltr_doc_date
END =
CASE '01'
WHEN '01' THEN sltr_pstng_date
ELSE sltr_doc_date
END
) thirty_days,
from glas_sl_transactions
When i execute this query, an error is ocurring near 'where'. How do I avoid this? If possible, please also tell me how to shorten this query.
Somewhere deep in the middle of that query, you have FROM WHERE - ie. you are missing a table name after the FROM.
Also, you can make it shorter by removing all the CASE '1' WHEN '1' THEN bits, since '1' is always '1'.
Edit: Ok, here's my reformatting of it:
( SELECT
SUM(
CONVERT(
FLOAT,
CASE '01'
WHEN '01' THEN
CASE SIGN((sltr_tran_amt - ISNULL(sltr_matched_amt, 0)))
WHEN 1 THEN
CASE DBO.glas_aging_oth(CONVERT(DATETIME, '2009/04/04') - FLOOR(sltr_pstng_date))
WHEN 0 THEN (sltr_tran_amt - ISNULL(sltr_matched_amt, 0))
ELSE 0
END
ELSE 0
END
WHEN '02' THEN
CASE SIGN((sltr_tran_amt - ISNULL(sltr_matched_amt, 0)))
WHEN -1 THEN
CASE DBO.glas_aging_oth(CONVERT(DATETIME, '2009/04/04') - FLOOR(sltr_doc_date))
WHEN 0 THEN (sltr_tran_amt - ISNULL(sltr_matched_amt, 0))
ELSE 0
END
ELSE 0
END
END
)
)
FROM
WHERE
CASE '01'
WHEN '01' THEN sltr_pstng_date
ELSE sltr_doc_date
END =
CASE '01'
WHEN '01' THEN sltr_pstng_date
ELSE sltr_doc_date
END
) thirty_days,
from glas_sl_transactions
So it looks like you are also missing an END in that gap before the first closing bracket above the FROM.
Also, it contains a lot of code that will never be executed. Eg.
CASE '01'
WHEN '01' /* always executed */
WHEN '02' /* never executed */
END
The where-clause also boils down to 1=1, and can therefore be removed.
In conclusion, here's what I think it should look like.
SELECT SUM( CONVERT(
FLOAT,
CASE SIGN((sltr_tran_amt - ISNULL(sltr_matched_amt, 0)))
WHEN 1 THEN
CASE DBO.glas_aging_oth(CONVERT(DATETIME, '2009/04/04') - FLOOR(sltr_pstng_date))
WHEN 0 THEN (sltr_tran_amt - ISNULL(sltr_matched_amt, 0))
ELSE 0
END
ELSE 0
END
))
from glas_sl_transactions