Update multiple variables in a single query - sql

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...

Related

SQL code to project how many clients will reach age 55 each month for a year

I am trying to get the number of clients who are currently >= age 55, which I've managed, but next I want to find out how many people will be >= 55 in a month's time, then in 2 month's time etc up to 12 months.
Here is what I have so far, but I'm not sure how to go about the next bit. Any help greatly appreciated! Thanks.
SELECT
SUM(CASE
WHEN [C].[BirthDate] > dateadd(year, -54, getdate()) AND [E].[MfChk4] = '0'
THEN 0
ELSE 1
END) AS [Age Eligible]
FROM
[dbo].[CR_Entity] [E]
LEFT OUTER JOIN [dbo].[CR_RefMaster] [RM]
ON [RM].[EntCode] = [E].[EntClient]
AND [RM].[Status] = '0'
LEFT OUTER JOIN [dbo].[Compliance] [C]
ON [C].[AddrCode] = [RM].[RefCode]
The result I want for the next bit will be something like...
You would have to write multiple case statements like:
SUM
(CASE WHEN [C].[BirthDate] > dateadd(month,-54*12+1, getdate())
AND [E].[MfChk4] = '0'
THEN 0 ELSE 1 END) AS Month1,
SUM
(CASE WHEN [C].[BirthDate] > dateadd(month,-54*12+2, getdate())
AND [E].[MfChk4] = '0'
THEN 0 ELSE 1 END) AS Month2,
.
.
.
SUM
(CASE WHEN [C].[BirthDate] > dateadd(month,-54*12+12, getdate())
AND [E].[MfChk4] = '0'
THEN 0 ELSE 1 END) AS Month12
To create the Naming convention you are looking, for you would have to use Dynamic SQL. You might have to change the query a bit, but the basics of it is:
--Declaring and calculating the Column Names
declare #test1 nvarchar(max),
#test2 nvarchar(max),
#test12 nvarchar(max)
set #test1='['+CAST(FORMAT(DATEADD(month,1,GETDATE()),'MMM-yy') as Varchar(20))+']'
set #test2='['+CAST(FORMAT(DATEADD(month,2,GETDATE()),'MMM-yy') as Varchar(20))+']'
.
.
.
set #test12='['+CAST(FORMAT(DATEADD(month,12,GETDATE()),'MMM-yy') as Varchar(20))+']'
--Writing the Dynamic Sql text
DECLARE #sql nvarchar(max)
SELECT #sql = N'SELECT SUM (CASE WHEN [C].[BirthDate] > dateadd(year, -54, getdate())
AND [E].[MfChk4] = ''0''
THEN 0 ELSE 1 END) AS [Age Eligible],
SUM
(CASE WHEN [C].[BirthDate] > dateadd(month,-54*12+1, getdate())
AND [E].[MfChk4] = ''0''
THEN 0 ELSE 1 END) AS' + #test1 + ',
SUM
(CASE WHEN [C].[BirthDate] > dateadd(month,-54*12+2, getdate())
AND [E].[MfChk4] = ''0''
THEN 0 ELSE 1 END) AS' + #test2 + ',
.
.
.
SUM
(CASE WHEN [C].[BirthDate] > dateadd(month,-54*12+12, getdate())
AND [E].[MfChk4] = ''0''
THEN 0 ELSE 1 END) AS' + #test12 + '
FROM [dbo].[CR_Entity] [E]
LEFT OUTER JOIN [dbo].[CR_RefMaster] [RM] ON [RM].[EntCode] = [E].[EntClient] AND [RM].[Status] = ''0''
LEFT OUTER JOIN [dbo].[Compliance] [C] ON [C].[AddrCode] = [RM].[RefCode]'
--Executing the Dynamic Sql query
EXEC sp_executesql #sql
You might want to start with one case statement to understand how it works and then implement it for the entire data.

Combine multiple queries in 1 return row

I have a query which should return 1 row for each DetectorID. What we currently have is the following:
DECLARE #StartDate datetime SET #StartDate = '2017-12-01 00:00'
DECLARE #EndDate datetime select #EndDate ='2018-01-01 00:00'
DECLARE #Limit1 real SET #Limit1 = 200; DECLARE #AssenLimit1 real SET #AssenLimit1 = 0;
DECLARE #Limit2 real SET #Limit2 = 300; DECLARE #AssenLimit2 real SET #AssenLimit2 = 0;
DECLARE #Limit3 real SET #Limit3 = 350; DECLARE #AssenLimit3 real SET #AssenLimit3 = 0;
DECLARE #Limit4 real SET #Limit4 = 400; DECLARE #AssenLimit4 real SET #AssenLimit4 = 0;
DECLARE #Limit5 real set #Limit5 = 500; DECLARE #AssenLimit5 real SET #AssenLimit5 = 0;
SELECT DetectorID, AVG(ValidWIM) AS 'PI_mean_WIM',
COUNT(ValidWIM) AS 'PI_mean_WIM2',
COUNT(CASE
WHEN ValidWIM > 0.5 THEN ValidWIM ELSE NULL END)
AS 'PI_mean_WIM3'
,AVG((ValidWDD_Left+ValidWDD_Right)/2) AS 'PI_mean_WDD'
,COUNT(ValidWDD_Left) AS 'PI_mean_WDD2'
,COUNT (CASE
WHEN (ValidWDD_Left>0.5 AND ValidWDD_Right>0.5) THEN ValidWDD_Left ELSE NULL END)
AS PI_mean_WDD3
,COUNT(CASE
WHEN AxleLoad IS NOT NULL Then TrainPassageInformationID ELSE NULL END)
AS 'nWheels'
, COUNT(CASE
WHEN (PeakForceLeft > #Limit1 OR PeakForceRight>#Limit1) THEN TrainPassageInformationID ELSE NULL END)
AS 'n>200'
, COUNT(CASE
WHEN (PeakForceLeft > #Limit2 OR PeakForceRight>#Limit2) THEN TrainPassageInformationID ELSE NULL END)
AS 'n>300'
, COUNT(CASE
WHEN (PeakForceLeft > #Limit3 OR PeakForceRight>#Limit3) THEN TrainPassageInformationID ELSE NULL END)
AS 'n>350'
, COUNT(CASE
WHEN (PeakForceLeft > #Limit4 OR PeakForceRight>#Limit4) THEN TrainPassageInformationID ELSE NULL END)
AS 'n>400'
, COUNT(CASE
WHEN (PeakForceLeft > #Limit5 OR PeakForceRight>#Limit5) THEN TrainPassageInformationID ELSE NULL END)
AS 'n>500'
From WheelDamage
where (TimeOfAxle > #StartDate AND TimeOfAxle < #EndDate) and DetectorID in (11,12)
GROUP BY DetectorID
order by DetectorID asc
SELECT DetectorID,
AVG(PeakForceLeft) AS 'NoiseLeft' FROM WheelDamage as t
where PeakForceLeft in (
select top 10 percent PeakForceLeft
from wheeldamage as tt
where tt.WheelDamageID = t.WheelDamageID AND tt.PeakForceLeft <> 0 AND tt.PeakForceLeft IS NOT NULL AND (t.TimeOfAxle > #StartDate AND t.TimeOfAxle < #EndDate)
order by tt.PeakForceLeft asc)
Group By DetectorID
order by DetectorID asc
SELECT DetectorID,
AVG(PeakForceRight) AS 'NoiseRight' FROM WheelDamage as t
where PeakForceLeft in (
select top 10 percent PeakForceRight
from wheeldamage as tt
where tt.WheelDamageID = t.WheelDamageID AND tt.PeakForceRight <> 0 AND tt.PeakForceLeft IS NOT NULL AND (t.TimeOfAxle > #StartDate AND t.TimeOfAxle < #EndDate)
order by tt.PeakForceLeft asc)
Group By DetectorID
order by DetectorID asc
SELECT DetectorId, COUNT (DateTime) AS 'Tags1'
FROM [TagPassage]
WHERE Valid = 1 AND (DateTime > #StartDate AND DateTime < #EndDate)
GROUP by DetectorID
Order by DetectorID asc
SELECT DetectorID, COUNT(CASE
WHEN (TotalWeight=0 OR TotalWeight IS NULL) AND (HasTrainStandStill<>1 OR HasTrainStandStill IS NULL) THEN (TrainPassageInformationID) ELSE NULL END) AS 'notAnalyzed'
, SUM (TotalWeight) AS 'TotalWeight'
FROM TrainPassageInformation
WHERE (Datetime > #StartDate AND Datetime < #EndDate)
Group By DetectorID
order by DetectorID asc
This is returing 5 new rows which I understand. This is because i have 5 select statements. However, I need to know how i can put the bottom 4 select statements in the top one so that it will only return 1 row.
I have tried with Select(Select X xxx). But that gave the error that it is returning more then 1 rows.
The image above is showing the current result. I want the bottom 4 tables to be columns in the first table.
can you just join/left join all the scripts together as table and link by DetectorID, then u can select the columns from the 4 scripts at the bottom to the right.

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

Improve SQL Server query

I have to improve this query, that works very well.
DECLARE #timTimeout int,
#iniDate varchar(20),
#endDate varchar(20)
SET #iniDate = '2014-07-20 00:00:00'
SET #endDate = '2014-11-24 23:59:59'
SET #timTimeout = 4000
SET ANSI_WARNINGS OFF
SELECT
'Approved (0200)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0200' THEN 1 END), 0),
'Approved Off (0220)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0220' THEN 1 END), 0),
'Cancel (0400)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0400' THEN 1 END), 0),
'Regret (0420)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0420' THEN 1 END), 0),
'TOTAL' = COUNT(*),
'Time-outs' = ISNULL(SUM(CASE WHEN DATEDIFF(ms, DateMsgIncome, DateMsgSent) > #timTimeout THEN 1 END), 0),
'Disponibility (%)' = (1 - CAST(ISNULL(SUM(CASE WHEN DATEDIFF(ms, DateMsgIncome, DateMsgSent) > #timTimeout THEN 1 END), 0) as money) / COUNT(*)) * 100
FROM Message (NOLOCK)
WHERE DateMsgIncome BETWEEN #iniDate AND #endDate
AND CodMsgIncome IN ('0200', '0220', '0400', '0420', '0800', '0900', '9080', '9085')
AND DescMsgIncome <> '0220'
Now, I have to prepare a report with Total data organized by month.
The output disered seems like this:
Approved (0200) | Approved Off (0220) | Cancel | Total | Time-outs | Disponibility (%)
July | 35 15 12 62 0 100.00
.
.
.
EDIT:
It is only one table on my query.
Table Message:
DateMsgIncome date,
DateMsgSent date,
CodMsgIncome varchar(4),
DescMsgIncome varchar(4),
CodMsgAnswer int.
Any suggestion is welcome.
Thanks in advance.
I ran your query through a code formatter to help clean it up. I also change the variable declaration since you didn't seem to understand what I was saying. For the record, the way you had it coded you might have missed some rows in the last few milliseconds of the day.
I changed the DATEDIFF function to use the datepart name spelled out because it is just too easy use the wrong abbreviation and get it wrong. I also simplified the calculation for the last column. The cast to money was not needed if you change the 1 - to 1.0 -. You should avoid using reserved words for object names and avoid spaces in column names. Let the front end do this kind of pretty formatting.
I also added the soon the be required WITH keyword when using table hints. (I would recommend understand what NOLOCK really means before using it).
DECLARE #timTimeout int
, #iniDate date
, #endDate date
SET #iniDate = '2014-07-20'
SET #endDate = '2014-11-25'
SET #timTimeout = 4000
SELECT MONTH(DateMsgIncome) as MyMonthColumn
, 'Approved (0200)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0200' THEN 1 END), 0)
, 'Approved Off (0220)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0220' THEN 1 END), 0)
, 'Cancel (0400)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0400' THEN 1 END), 0)
, 'Regret (0420)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0420' THEN 1 END), 0)
, 'TOTAL' = COUNT(*)
, 'Time-outs' = ISNULL(SUM(CASE WHEN DATEDIFF(MILLISECOND, DateMsgIncome, DateMsgSent) > #timTimeout THEN 1 END), 0)
, 'Disponibility (%)' = (1.0 - ISNULL(SUM(CASE WHEN DATEDIFF(MILLISECOND, DateMsgIncome, DateMsgSent) > #timTimeout THEN 1 END), 0) / COUNT(*)) * 100
FROM [Message] WITH (NOLOCK) --Ack!!! I wouldn't let this fly on my system due to inconsistencies with this hint unless accuracy is not important (like
WHERE DateMsgIncome >= #iniDate
AND DateMsgIncome < #endDate
AND CodMsgIncome IN
(
'0200'
, '0220'
, '0400'
, '0420'
, '0800'
, '0900'
, '9080'
, '9085'
)
AND DescMsgIncome <> '0220'
GROUP BY MONTH(DateMsgIncome)

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.