Improve SQL Server query - sql

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)

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.

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

SQL Time Conversion

I am having trouble with a conversion of time.
I have a table called 'TotalTime' which is set to INT and holds the time in seconds only. I want to convert these seconds to days, hours, minutes, seconds e.g. 01d 09:26:43.
Now I will show you the code I am using:
SELECT [BuildID],[Product],[Program],
SUM(CASE WHEN [State] = 'Running' THEN cast(TotalTime as INT) ELSE 0 END) AS [Running],
SUM(CASE WHEN [State] = 'Break' THEN cast(TotalTime as INT) ELSE 0 END) AS [Break]
FROM [line_log].[dbo].[Line1Log]
GROUP BY [BuildID], [Product], [Program]
So as you can see I am grouping the [State] column and would like to display the results of 'TotalTime' in the format I mentioned above.
Now I have tried this code but it will not work as I cannot convert INT to VARCHAR
SELECT [BuildID],[Product],[Program],
SUM(CASE WHEN [State] = 'Running' THEN CAST(FLOOR(TotalTime / 86400) AS VARCHAR(10))+'d ' + CONVERT(VARCHAR(5), DATEADD(SECOND, TotalTime, '19000101'), 8) ELSE 0 END) AS [Running]
FROM [line_log].[dbo].[Line1Log]
GROUP BY [BuildID], [Product], [Program]
The above would not display it in the exact format I wanted either.
Just wondering if someone would be willing to help me on this one?
Thanks for taking the time to read this :)
You should convert calculated seconds after summing and grouping:
And use VARCHAR(8) instead of VARCHAR(5).
SELECT [BuildID],[Product],[Program],
CAST(FLOOR([Running] / 86400) AS VARCHAR(10))+'d ' + CONVERT(VARCHAR(8), DATEADD(SECOND, [Running], '19000101'), 8) AS [Running],
CAST(FLOOR([Break] / 86400) AS VARCHAR(10))+'d ' + CONVERT(VARCHAR(8), DATEADD(SECOND, [Break], '19000101'), 8) AS [Break]
FROM (
SELECT [BuildID],[Product],[Program],
SUM(CASE WHEN [State] = 'Running' THEN cast(TotalTime as INT) ELSE 0 END) AS [Running],
SUM(CASE WHEN [State] = 'Break' THEN cast(TotalTime as INT) ELSE 0 END) AS [Break]
FROM [line_log].[dbo].[Line1Log]
GROUP BY [BuildID], [Product], [Program]
) T

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.

Combining SQL Server Queries

I am using SQL Server and I have two tables and I would like to combine into one query that I can use to fill a gridview.
Table1 dbo.Work
UID (PK, int)
Tech_Ticket (int)
RMA_Ticket (int)
Region (nchar10)
Completed (nchar10)
FA (nchar10)
Agent (nvarchar50)
Tracking (nvarchar50)
Date_Added (date)
Date_Updated (date)
Table2 dbo.Orders
UID (PK, int)
Order (int)
Agent (nvarchar50)
Ticket (int)
Notes (nvarchar50)
Right now I have them setup as two separate queries and two separate tables.
Query1:
SELECT [Agent],
SUM(CASE WHEN [Date_Added] BETWEEN #startDate AND #endDate THEN 1 ELSE 0 END) AS 'New ',
SUM(CASE WHEN [Date_Updated] BETWEEN #startDate AND #endDate THEN 1 ELSE 0 END) AS 'Worked',
SUM(CASE WHEN [Completed] = 'yes' AND [Date_Updated] BETWEEN #startDate AND #endDate THEN 1 ELSE 0 END) AS 'Completed',
SUM(CASE WHEN [Failure_Analysis] = 'yes' AND [Date_Updated] BETWEEN #startDate AND #endDate THEN 1 ELSE 0 END) AS 'FA'
FROM Work
GROUP BY [Agent]
Query2:
SELECT [Agent]
SUM(CASE WHEN [Date] BETWEEN #startDate AND #endDate THEN 1 ELSE 0 END) AS 'Orders'
FROM Orders
GROUP BY [Agent]
Is there a way to combine these two queries into one?
You can JOIN them. Assuming that Work is the main table, it should be like this:
SELECT A.*, B.Orders
FROM ( SELECT [Agent],
SUM(CASE WHEN [Date_Added] BETWEEN #startDate AND #endDate THEN 1 ELSE 0 END) AS 'New',
SUM(CASE WHEN [Date_Updated] BETWEEN #startDate AND #endDate THEN 1 ELSE 0 END) AS 'Worked',
SUM(CASE WHEN [Completed] = 'yes' AND [Date_Updated] BETWEEN #startDate AND #endDate THEN 1 ELSE 0 END) AS 'Completed',
SUM(CASE WHEN [Failure_Analysis] = 'yes' AND [Date_Updated] BETWEEN #startDate AND #endDate THEN 1 ELSE 0 END) AS 'FA'
FROM Work
GROUP BY [Agent]) A
LEFT JOIN (SELECT [Agent]
SUM(CASE WHEN [Date] BETWEEN #startDate AND #endDate THEN 1 ELSE 0 END) AS 'Orders'
FROM Orders
GROUP BY [Agent]) B
ON A.[Agent] = B.[Agent]