I am trying to create a report that shows a single item(store_Product) purchased by store location(store_ID).
There are total 3 types of store_Product: product_A, product_B, and product_C.
There are over a thousand unique store_ID.
My issue is that some unique store_ID have multiple store_Products and I need to shrink the query so it returns only unique store_IDs
These are the rules of condition:
if a store has product_B and any other product, one unique store_ID record would have product_B as the store_Product value
if a store has product_A and product_C, one unique store_ID record would have product_A as the store_Product value
if a store has only one record then store_Product remains unchanged.
So the example below explains what I have on the left and what I want it to look like on the right:
I am using SQL server 2014 building the report in SSRS.
Really appreciate any help!
EDIT: What i have so far:
SELECT [store_ID]
,MIN(CASE WHEN store_product = 'product_B' THEN '1_product_B'
WHEN store_product = 'product_A' THEN '2_product_A'
ELSE '3_product_C' END) AS 'Prob_Group'
,CASE
WHEN (DATEDIFF(MINUTE, Opened_Time, GETDATE())) * 1.0 / 60 < '24'
THEN '0 - 24 HRs'
WHEN (DATEDIFF(MINUTE, Opened_Time, GETDATE())) * 1.0 / 60 >= '24'
AND (DATEDIFF(MINUTE, Opened_Time, GETDATE())) * 1.0 / 60 < '48'
THEN '24 - 48 HRs'
WHEN (DATEDIFF(MINUTE, Opened_Time, GETDATE())) * 1.0 / 60 >= '48'
AND (DATEDIFF(MINUTE, Opened_Time, GETDATE())) * 1.0 / 60 < '72'
THEN '48 - 72 HRs'
ELSE 'Over 168 HRs'
END AS 'Hour_Range'
FROM myTable
WHERE *filters*
GROUP BY [store_ID]
,CASE
WHEN (DATEDIFF(MINUTE, Opened_Time, GETDATE())) * 1.0 / 60 < '24'
THEN '0 - 24 HRs'
WHEN (DATEDIFF(MINUTE, Opened_Time, GETDATE())) * 1.0 / 60 >= '24'
AND (DATEDIFF(MINUTE, Opened_Time, GETDATE())) * 1.0 / 60 < '48'
THEN '24 - 48 HRs'
WHEN (DATEDIFF(MINUTE, Opened_Time, GETDATE())) * 1.0 / 60 >= '48'
AND (DATEDIFF(MINUTE, Opened_Time, GETDATE())) * 1.0 / 60 < '72'
THEN '48 - 72 HRs'
ELSE 'Over 168 HRs'
END
ORDER BY [store_ID]
I'm being very sneaky here:
SELECT store_id,
MIN( CASE WHEN store_Product = "product_B" THEN "1_product_B"
WHEN store_Product = "product_A" THEN "2_product_A"
ELSE "3_product_C"
END) as Product
FROM YourTable
GROUP BY store_id
So if the store has product_B, the result would be 1_product_B, not matter if are product_A and product_C.
Same if not product_B the minimum between 2_product_A and 3_product_C is 2_product_A also works if only has product_A.
After you have the result you can remove the first two characters
WITH cte as (
SELECT store_id,
MIN( CASE WHEN store_Product = "product_B" THEN "1_product_B"
WHEN store_Product = "product_A" THEN "2_product_A"
ELSE "3_product_C"
END) as Product
FROM yourTable
GROUP BY store_id
)
SELECT store_id, RIGHT(Product, LEN(Product) - 2) AS fixProductName
FROM CTE
Related
I have 2 columns which have an occupancy column and contains values of 0 and 1.
Here is an example:
After group by based on other columns, these columns will be combined and the average will be 0.5 since 0+1/2 = 0.5 or 1/2.
So how do I do this: case when avg(occupancy) = 1/2 or 0.5 then '1' else '0'?
I know something about SQL round down 1/2 to 0 or something along that lines
What I have tried:
case when
Avg(occupancy) = 1.0/2.0
Here is my full view code.
CREATE VIEW [iot].[v_test]
AS
SELECT
ro.[RoomCode],
ro.[RoomName],
ro.[DeviceID],
ro.[TpID],
CAST(avg(ro.[Temperature]) AS decimal(10, 1)) AS [Temperature],
CASE
WHEN avg(cast(occupancy as decimal)) between 0.01 and 1.0
THEN '1'
WHEN avg(cast(occupancy as decimal)) = 1/2.0
THEN '1'
ELSE
'0'
END AS Occupancy,
(DATEADD(HOUR, DATEPART(HOUR, ro.[LocalTime]), DATEADD( MINUTE, 30 * CAST((DATEDIFF(MINUTE, '19000101', ro.[LocalTime]) / 30) % 2 AS INT),
CAST(CAST(ro.[LocalTime] AS DATE) AS DATETIME)))) AS [Time],
ctt.[DAY],
cs.ClassroomStatus
FROM
[iot].[v_RoomOccupancy] ro
LEFT OUTER JOIN
[iot].[ClassTimeTable] ctt
ON ro.RoomCode = ctt.ROOMID
AND (ro.LocalTime
BETWEEN ctt.CLASSSTARTDATE AND ctt.CLASSENDDATE
)
CROSS APPLY
(
SELECT
CASE
WHEN (ro.LocalTime BETWEEN ctt.CLASSSTARTDATE AND ctt.CLASSENDDATE)
AND (cast(occupancy as decimal) between 0.1 and 1.0 )
THEN 'Booked And Occupied'
WHEN ((ro.LocalTime NOT BETWEEN ctt.CLASSSTARTDATE AND ctt.CLASSENDDATE) OR ( ctt.CLASSSTARTDATE IS NULL AND ctt.CLASSENDDATE IS NULL))
AND (cast(occupancy as decimal) between 0.1 and 1.0 )
THEN 'Not Booked but Occupied'
WHEN (ro.LocalTime BETWEEN ctt.CLASSSTARTDATE AND ctt.CLASSENDDATE)
AND cast(occupancy as decimal) <= 0.0
THEN 'Booked but Not Occupied'
WHEN ((ro.LocalTime NOT BETWEEN ctt.CLASSSTARTDATE AND ctt.CLASSENDDATE) OR (ctt.CLASSSTARTDATE IS NULL AND ctt.CLASSENDDATE IS NULL))
AND cast(occupancy as decimal) <= 0.0
THEN 'Not Booked and Not Occupied'
ELSE
'Null'
END AS ClassroomStatus
)AS cs
GROUP BY
ro.[RoomCode],
ro.[RoomName],
ro.[DeviceID],
ro.[TpID],
(DATEADD(HOUR, DATEPART(HOUR, ro.[LocalTime]), DATEADD( MINUTE, 30 * CAST((DATEDIFF(MINUTE, '19000101', ro.[LocalTime]) / 30) % 2 AS INT),
CAST(CAST(ro.[LocalTime] AS DATE) AS DATETIME)))),
ctt.[DAY],
cs.ClassroomStatus;
try this.
select case when avg(cast(occupancy as decimal)) in (.5, 1.0, 0) then 1 else 0 end
or
select case when avg(cast(occupancy as decimal)) between 0.0 and 1.0 then '1' else 'Error' end
I have a list of tasks,
for each I have a TaskID, startTime and StopTime as milliseconds from 1-1-1970 and a list of users (#Tasks).
I need to calculate the time spent by each user on the task splitted by day/night time, week or weekend, regular/overtime considering nighttime hours from 10:00 PM to 06:00 AM.
Surely there's a better solution but so far I got this:
IF OBJECT_ID('tempdb..#Tasks') IS NULL
BEGIN
create table #Tasks
(
TaskID nvarchar(50),
DateStart bigint,
DateStop bigint,
Staff nvarchar(100)
)
insert into #Tasks values
('C001',1554181200000,1554190200000,'john,jack'),
('C002',1554202800000,1554212700000,'tom,john'),
('C003',1554228000000,1554246900000,'john,franck'),
('C004',1554613200000,1554626700000,'john')
END
GO
declare
#UserName nvarchar(50)='john',
#DateFrom datetime='2019-04-01',
#DateTo datetime='2019-04-30',
#nStart time='06:00:00',
#nStop time='22:00:00'
select
startday as [Day],
sum([WeekDay]) as [WeekDay],
sum([WeekNight]) as [WeekNight],
sum([WeekendDay]) as [WeekendDay],
sum([WeekendNight]) as [WeekendNight],
sum([TotalMinutes]) as [TotalMinutes],
0 WeekDayOverTime,
0 WeekNightOvertime,
0 WeekendDayOvertime,
0 WeekendNightOvertime,
[UserName]
,timeframe
from
(
select
iif(isWeekend=1,NightMinutes,0) WeekendNight,
iif(isWeekend=0,NightMinutes,0) WeekNight,
iif(isWeekend=1,DayMinutes,0) WeekendDay,
iif(isWeekend=0,DayMinutes,0) [WeekDay],
TotalMinutes,
username,
startday,
timeframe
from
(
select
iif(Before6>0,Before6,0)+ iif(After22>0,After22,0) NightMinutes,
TotalMinutes-iif(Before6>0,Before6,0)- iif(After22>0,After22,0) DayMinutes,
TotalMinutes,
startday,
isWeekend,
UserName,
timeframe
from
(
Select
(t.datestop-t.datestart)/60000 TotalMinutes,
datediff(n,convert(time,DATEADD(SECOND,t.DateStart/1000,'1970-01-01')),#nStart) Before6,
datediff(n,#nStop,convert(time,DATEADD(SECOND,t.DateStop/1000,'1970-01-01'))) After22,
iif((((DATEPART(DW, convert(datetime,DATEADD(SECOND,t.DateStart/1000,'1970-01-01'))) - 1 ) + ##DATEFIRST ) % 7) IN (0,6),1,0) isWeekend,
convert(varchar(10),DATEADD(SECOND,t.DateStart/1000,'1970-01-01'),126) startday,
STUFF(( SELECT distinct ' ' + convert(varchar(5),DATEADD(SECOND,t.DateStart/1000,'1970-01-01'),108)+'-'+convert(varchar(5),DATEADD(SECOND,t.DateStop/1000,'1970-01-01'),108) AS [text()]
FROM #Tasks tt
--WHERE tt.taskID=t.TaskID
FOR XML PATH('') ), 1, 1, '' ) AS [timeframe],
#UserName UserName
FROM #Tasks t
WHERE t.Staff like '%'+#UserName+'%'
and DATEADD(SECOND,t.DateStart/1000,'1970-01-01') between #DateFrom and #DateTo
) z
) zz
) zzz
group by startday,username,timeframe
order by startday
I need now to :
1) group result by day, summing up WeekDay,WeekNight,WeekendDay,WeekendNight and TotalMinutes, and concatenating timeframe so to have for example on 2nd April "05:00-07:30|11:00-13:45|18:00-23:00"
2) Not sum up time between 12:00 and 12:30 (if applicable) since it is lunch time
3) considering that after 8 hours daily it has to be calculated as overtime, I have to split the total minutes between in time and overtime, but depending if overtime is by daytime or nighttime or on the weekend
4) eventually using a holiday table
in other words we should have this:
Day TotalMinutes WeekDay WeekNight WeekendDay WeekendNight WeekDayOverTime WeekNightOvertime WeekendDayOvertime WeekendNightOvertime UserName timeframe
02/04/2019 630 420 60 0 0 45 75 0 0 john 05:00-07:30|11:00-13:45|18:00-23:00
07/04/2019 225 0 0 165 60 0 0 0 0 john 05:00-08:45
because (on 2nd April) we have:
First Task:
60 minutes of Regular NightTime
90 minutes of Regular DayTime
Second Task:
165 minutes of Regular DayTime, but have to count only 135 due to lunch time
Third Task:
240 DayTime
75 NightTime
but since with Task 1 and 2 we sum up 285 minutes, only the first 185 Minutes of Third task are Regular DayTime: the remaining 45 are Overtime DayTime, and the following 75 of NightTime are actually OvertimeNightTime
In this approach the first CTE (properDates) get the Start and Stop Datetimes, then you don't need to repeat that formula over the query.
The second CTE(splittedMinutes) is to get the same data you get in your current approach, except for the first CROSS APPLY, which is splitting the timeframes crossing with lunch time. The second CROSS APPLY gets the number of minutes and isWeekend value.
In the third CTE(qualifiedMinutes) I am using a window partition to get the accumulated minutes and generate the overtimes when applies.
At the end I used a selective SUM to separate weekdays and weekends in the aggregates
;with properDates AS (
SELECT TaskID, DATEADD(SECOND,t.DateStart/1000,'1970-01-01') as DateStart,DATEADD(SECOND,t.DateStop/1000,'1970-01-01') as DateStop, Staff
FROM #Tasks t
WHERE Staff LIKE '%' + #UserName + '%'
), splittedMinutes AS (
select
CAST(p.DateStart AS DATE) as [Day],
TotalMinutes,
SUM(TotalMinutes) OVER (PARTITION BY CAST(p.DateStart AS DATE) ORDER BY b.start) AS cumulate,
TotalMinutes - EarlyMinutes - LateMinutes as DayTime,
EarlyMinutes + LateMinutes as NightTime,
isWeekend,
CONVERT(VARCHAR(5),b.Start,108) + '-' + CONVERT(VARCHAR(5),b.Stop,108) as [timeframe]
from properdates p
cross apply (
select CAST(p.DateStart As TIME) AS Start, #bStart as Stop WHERE CAST(p.DateStart AS TIME) < #bStart and CAST(p.DateStop AS TIME) > #bStart
union
select #bStop as Start, CAST(DateStop AS TIME) AS Stop WHERE CAST(p.DateStop AS TIME) > #bStop and CAST(p.DateStart AS TIME) < #bStop
union
select CAST(p.DateStart AS TIME) AS Start, CAST(p.DateStop AS TIME) AS Stop WHERE NOT (CAST(p.DateStart AS TIME) < #bStart and CAST(p.DateStop AS TIME) > #bStart) AND NOT (CAST(p.DateStop AS TIME) > #bStop and CAST(p.DateStart AS TIME) < #bStop)
) b
cross apply (
select
DATEDIFF(Minute, b.Start, b.Stop) as TotalMinutes,
(DATEDIFF(Minute, CAST(b.Start AS TIME), #nStart) + ABS(DATEDIFF(Minute, CAST(b.Start AS TIME), #nStart))) / 2 as EarlyMinutes,
(DATEDIFF(Minute, #nStop, CAST(b.Stop AS TIME)) + ABS(DATEDIFF(Minute, #nStop, CAST(b.Stop AS TIME)))) / 2 as LateMinutes,
CASE WHEN DATEPART(DW, p.DateStart) IN (1,7) THEN 1 ELSE 0 END AS isWeekend
) c
), qualifiedMinutes As (
SELECT Day, TotalMinutes, RegularDay, RegularNight, OvertimeDay, OvertimeNight, isWeekend, timeframe
FROM splittedMinutes
OUTER APPLY (
SELECT RegularDay = CASE WHEN cumulate <= #maxTime THEN DayTime WHEN DayTime - (cumulate - TotalMinutes - #maxTime) > 0 THEN ABS(cumulate - TotalMinutes - #maxTime) ELSE 0 END
) RD
OUTER APPLY (
SELECT OvertimeDay = DayTime - RegularDay
) OWD
OUTER APPLY (
SELECT RegularNight = CASE WHEN cumulate <= #maxTime THEN NightTime WHEN (cumulate - TotalMinutes - #maxTime + RegularDay) < 0 THEN NightTime + (cumulate - TotalMinutes - #maxTime + RegularDay) ELSE 0 END
) RWN
OUTER APPLY (
SELECT OvertimeNight = NightTime - RegularNight
) OWN
)
SELECT
Day,
#UserName and UserName,
SUM(TotalMinutes) AS TotalMinutes,
SUM(CASE WHEN isWeekend = 0 THEN RegularDay ELSE 0 END) AS WeekDay,
SUM(CASE WHEN isWeekend = 0 THEN RegularNight ELSE 0 END) AS WeekNight,
SUM(CASE WHEN isWeekend = 1 THEN RegularDay ELSE 0 END) AS WeekendDay,
SUM(CASE WHEN isWeekend = 1 THEN RegularNight ELSE 0 END) AS WeekendNight,
SUM(CASE WHEN isWeekend = 0 THEN OvertimeDay ELSE 0 END) AS WeekDayOverTime,
SUM(CASE WHEN isWeekend = 0 THEN OvertimeNight ELSE 0 END) AS WeekNightOvertime,
SUM(CASE WHEN isWeekend = 1 THEN OvertimeDay ELSE 0 END) AS WeekendDayOverTime,
SUM(CASE WHEN isWeekend = 1 THEN OvertimeNight ELSE 0 END) AS WeekendNightOvertime,
STUFF((SELECT '|' + timeframe FROM qualifiedMinutes tt WHERE tt.Day = q.Day ORDER BY timeframe FOR XML PATH('') ), 1, 1, '' ) AS [timeframe]
FROM qualifiedMinutes q
GROUP BY Day
I have a SQL Server database that has one data table that has one second data. The table has the following columns:
DataId
DataType
NumericValue
PostDate
WindSpeed is one data type
Wind Direction is a second
Ultimately I would like to be able to have a stored procedure that I can send a start and end datetime and an average time interval in minutes. What I have so far is the following and it is not working.
select
'avgWD' = case
when weather.OuvWithoutFlow > 180
then sum(weather.OuvWithoutFlow - 180)
when weather.OuvWithoutFlow < 180
then sum(weather.OuvWithoutFlow + 180)
else sum(weather.OuvWithoutFlow + 0)
end
from
(select
(atan(((-1/(cast(count(*) as float)))*(sum(WD_sin)))/((-1/(cast(count(*) as float)))*(sum(WD_cos))))) as OuvWithoutFlow
from
(select
d_WS.numericvalue as WS,
sin(d_WD.WD) as WD_sin,
cos(d_WD.WD) as WD_cos,
d_WD.WD, d_WS.PostDate
from
(select Top 10 *
from datum
where datum.DatTypeID = #ParameterID_WS) as d_WS
cross apply
(select numericvalue as WD
from datum
where datum.DatTypeID = #ParameterID_WD
and datum.postdate = d_WS.postdate) as d_WD) wind
) weather
group by
weather.OuvWithoutFlow
Using this data set it returns 180.784167303869 which is wrong.
WS WD_Sin WD_COS WD PostDate
0.720000 0.632170969166108 0.344615533230271 214.700000 2018-05-21 21:50:03.0000000
0.977000 -0.520565399773975 0.82676518102673 200.500000 2018-05-21 21:50:04.0000000
1.132000 1.01064916139673 -0.509913985460376 203.100000 2018-05-21 21:50:05.0000000
1.183000 -0.859512457376702 -0.812851361328911 211.300000 2018-05-21 21:50:06.0000000
0.977000 -0.478215500921105 0.851961815270366 219.400000 2018-05-21 21:50:07.0000000
1.183000 0.555198984923194 1.04462581202087 220.400000 2018-05-21 21:50:08.0000000
0.926000 0.922867100571996 0.0761072577474554 221.400000 2018-05-21 21:50:09.0000000
1.029000 -0.686290821523267 -0.76671109832382 217.500000 2018-05-21 21:50:10.0000000
0.977000 0.102716204322373 0.971585498743988 226.300000 2018-05-21 21:50:11.0000000
1.080000 0.489014249853966 -0.962946033503313 216.300000 2018-05-21 21:50:12.0000000
Upworks helped out.
SET NOCOUNT ON;
;WITH
WindDirection
AS (SELECT d.PostDate,
d.NumericValue AS Direction
FROM Datum AS d
WHERE ( d.ParameterId = #ParameterID_WD )),
WindSpeed
AS (SELECT d.PostDate,
d.NumericValue AS Speed
FROM Datum AS d
WHERE ( d.ParameterId = #ParameterID_WS )),
DatumCombined
AS (SELECT wd.postdate,
wd.direction,
ws.speed
FROM WindDirection AS wd
INNER JOIN WindSpeed AS ws
ON wd.PostDate = ws.PostDate),
DirectionRadians
AS (SELECT dc.Direction * Pi() / 180. AS [radians],
dc.PostDate,
dc.Speed
FROM DatumCombined AS dc),
postdate
AS (SELECT Dateadd(minute, Datediff(minute, 0, dr.PostDate) / #interval * #interval, 0 ) AS postdate,
x = Avg(Sin(radians) * dr.Speed),
y = Avg(Cos(radians) * dr.Speed)
FROM DirectionRadians AS dr
GROUP BY Dateadd(minute, Datediff(minute, 0, dr.PostDate) / #interval * #interval, 0)),
AverageRadiansByIntervals
AS (SELECT di.PostDate,
CASE
WHEN di.x >= 0
AND di.y >= 0 THEN 0 + Atan(di.x/di.y)
WHEN di.x >= 0
AND di.y < 0 THEN Pi() - Atan(di.x /-di.y)
WHEN di.x < 0
AND di.y < 0 THEN Pi() + Atan(-di.x/-di.y)
WHEN di.x < 0
AND di.y >= 0 THEN 2 * Pi() - Atan(-di.x /di.y)
END AS AverageRadians
FROM PostDate AS di)
SELECT ar.postdate,
ar.AverageRadians * 180. / Pi() numericvalue
FROM AverageRadiansByIntervals AS ar
WHERE ar.PostDate >= #StartDate AND ar.PostDate < #EndDate
ORDER BY ar.PostDate
I am having some difficulty in trying to figure out something, lets say I have a date and time;
And I want to add 180 minutes to it so;
SELECT DATEADD(MINUTE,180,'2018-05-24 15:00')
This would give me answer of "2018-05-24 18:00" but I want to do it in a range so ADD the minutes if you are between 09:00 - 17:00 so something like this;
SELECT DATEADD(MINUTES,180,'2018-05-24 15:00') WHERE '2018-05-24 15:00' BETWEEN '2018-05-24 09:00' AND '2018-05-24 17:00'
So the answer to this would be "2018-05-25 10:00"
Was hard, but this should work for all your cases. This solution works for any amount of (positive) minutes and result will always be inside the parametrized hours, adding the corresponding amount of days.
DECLARE #RangeHourStart INT = 9
DECLARE #RangeHourEnd INT = 17
DECLARE #MinutesToAdd INT = 120
DECLARE #Date DATETIME = '2018-05-24 15:00'
SELECT
FinalDate = CASE
WHEN -- When final hour exceeds the range hour
DATEPART(HOUR, #Date) * 60 +
DATEPART(MINUTE, #Date) +
#MinutesToAdd % ((#RangeHourEnd - #RangeHourStart) * 60) > #RangeHourEnd * 60
THEN
DATEADD(HOUR, -1 * (#RangeHourStart - 1),
DATEADD(DAY, 1,
DATEADD(MINUTE, #MinutesToAdd % ((#RangeHourEnd - #RangeHourStart) * 60),
DATEADD(
DAY,
#MinutesToAdd / ((#RangeHourEnd - #RangeHourStart) * 60),
#Date))))
ELSE
DATEADD(MINUTE, #MinutesToAdd % ((#RangeHourEnd - #RangeHourStart) * 60),
DATEADD(
DAY,
#MinutesToAdd / ((#RangeHourEnd - #RangeHourStart) * 60),
#Date))
END
I made it so you don't need to hard-code any value.
This doesn't look particularly pretty, however...
USE Sandbox;
GO
CREATE TABLE Times (DateNTime datetime2(0));
INSERT INTO Times
VALUES ('20180520 10:00:00'),
('20180520 15:20:00'),
('20180521 09:32:00'),
('20180521 14:17:00'),
('20180522 16:54:00'),
('20180523 12:46:00'),
('20180524 15:32:00');
GO
SELECT *
FROM Times;
GO
SELECT T.DateNTime,
CASE WHEN CONVERT(time,T.DateNTime) <= '14:00' THEN DATEADD(MINUTE, 180,T.DateNTime)
ELSE DATEADD(MINUTE, 180 - DATEDIFF(MINUTE,T.DateNTime,DATEADD(HOUR,17,DATEADD(DAY, DATEDIFF(DAY, 0, T.DateNTime),0))), DATEADD(HOUR,9,DATEADD(DAY, DATEDIFF(DAY, 0, T.DateNTime) + 1,0))) END
FROM Times T;
GO
DROP TABLE Times;
you can try this:
DECLARE #input DATETIME='2018-05-24 15:00'
DECLARE #min INT=180
SELECT CASE WHEN DATEADD(MINUTE,#min,#input)>DATEADD(HOUR, 17,DateAdd(Day, Datediff(Day,0, #input), 0))
THEN DATEADD(MINUTE,
DATEDIFF(MINUTE,
DATEADD(HOUR, 17,
DATEADD(Day,
DATEDIFF(Day,0, #input),
0)
),
DATEADD(MINUTE,#min,#input)),
DATEADD(Hour,9,
DATEADD(Day,1,
DateAdd(Day,
Datediff(Day,0, #input),
0)
)
)
)
ELSE DATEADD(MINUTE,#min,#input)
END
I think it is some funky rounding issue going on here, but I don't know how the inner sql works. So maybe someone can help.
SELECT COUNT(Id) TotalReferrals,
SUM(CASE WHEN NHSCommunicationNeed1_Id IS NOT NULL THEN 1 ELSE 0 END) NHSCommNeed1Total,
SUM(CASE WHEN NHSCommunicationNeed2_Id IS NOT NULL THEN 1 ELSE 0 END) NHSCommNeed2Total,
SUM(CASE WHEN NHSCommunicationNeed3_Id IS NOT NULL THEN 1 ELSE 0 END)
NHSCommNeed3Total
INTO #Totals
FROM DDS.Referrals
Gives me the following result set
TotalReferrals NHSCommNeed1Total NHSCommNeed2Total NHSCommNeed3Total
1008 1008 508 508
Then when I do this
SELECT
SUM((NHSCommNeed1Total / TotalReferrals) * 100) NHSCommNeed1Percent,
SUM((NHSCommNeed2Total / TotalReferrals) * 100) NHSCommNeed2Percent,
SUM((NHSCommNeed3Total / TotalReferrals) * 100) NHSCommNeed3Percent
FROM #Totals
I get this?
NHSCommNeed1Percent NHSCommNeed2Percent NHSCommNeed3Percent
100 0 0
Can someone explain what is going on and how do I fix it
The result of NHSCommNeed1Total / (TotalReferrals is calculated as integer, therefore it ends up to 0. To enforce making it decimal or double just multiply it with 1.0:
SELECT
SUM((NHSCommNeed1Total / (TotalReferrals * 1.0)) * 100) NHSCommNeed1Percent,
SUM((NHSCommNeed2Total / (TotalReferrals * 1.0)) * 100) NHSCommNeed2Percent,
SUM((NHSCommNeed3Total / (TotalReferrals * 1.0)) * 100) AS NHSCommNeed3Percent
FROM #Totals
Yes sure, no need for two statements, you can use INSERT INTO SELECT:
WITH CTE
AS
(
SELECT COUNT(Id) TotalReferrals,
SUM(CASE WHEN NHSCommunicationNeed1_Id IS NOT NULL THEN 1.0 ELSE 0 END) NHSCommNeed1Total,
SUM(CASE WHEN NHSCommunicationNeed2_Id IS NOT NULL THEN 1.0 ELSE 0 END) NHSCommNeed2Total,
SUM(CASE WHEN NHSCommunicationNeed3_Id IS NOT NULL THEN 1.0 ELSE 0 END)
NHSCommNeed3Total
FROM DDS.Referrals
)
INSERT INTO SomeOtherTable(NHSCommNeed1Total,NHSCommNeed2Total ,NHSCommNeed3Total)
SELECT
SUM((NHSCommNeed1Total / (TotalReferrals * 1.0)) * 100) AS NHSCommNeed1Percent,
SUM((NHSCommNeed2Total / (TotalReferrals * 1.0)) * 100) NHSCommNeed2Percent,
SUM((NHSCommNeed3Total / (TotalReferrals * 1.0)) * 100) AS NHSCommNeed3Percent
FROM CTE;
If you want an all in one statement this should work
SELECT
SUM(CASE WHEN NHSCommunicationNeed1_Id IS NOT NULL THEN 1.0 ELSE 0.0 END) / COUNT(Id) as NHSCommNeed1Percent,
SUM(CASE WHEN NHSCommunicationNeed2_Id IS NOT NULL THEN 1.0 ELSE 0.0 END) / COUNT(Id) as NHSCommNeed2Percent,
SUM(CASE WHEN NHSCommunicationNeed3_Id IS NOT NULL THEN 1.0 ELSE 0.0 END) / COUNT(Id) as NHSCommNeed3Percent
FROM DDS.Referrals