Embedded CASE with expressions in SQL Server 2008 - sql-server-2008

Hi SQL SVR 2008 gurus.
As a SQL newbie, I'm hoping for some direction.I've got a SELECT statement that needs to check an expression against a field value for each worker to see if they qualify for a paid lunch break. The value of the number of hours they need to work is in their workers table profile in a field called minimumhours, and I get their hours worked from an expression against a login and logout field in a table called workflow. The statement I've pieced together is as follows (the startdate and enddate will be user selectable values):
DECLARE #StartDate AS DateTime
SET #StartDate = CAST('03/25/2012' AS DATE)
DECLARE #EndDate AS DateTime
SET #EndDate = CAST('03/31/2012' AS DATE)
SELECT
w.Firstname
,w.Lastname
,wf.Login
,wf.logout
,ROUND(CAST(DATEDIFF(MI, wf.Login, wf.Logout) AS DECIMAL)/60,2) AS [Hours]
,w.LunchDeduction AS [Lunch Deduction]
CASE [HoursBilled] =
WHEN DATEDIFF(hour, wf.Login, wf.Logout) < wf.MinimumHours THEN
ROUND(CAST(DATEDIFF(MI, wf.Login, wf.Logout) AS DECIMAL)/60,-
w.LunchDeduction,2)
WHEN DATEDIFF(hour, wf.Login, wf.Logout) >= wf.MinimumHours THEN
ROUND(CAST(DATEDIFF(MI, wf.Login, wf.Logout) AS DECIMAL)/60,- 0,2)
END
FROM Workers AS w
JOIN Workflow AS wf
ON wf.LoggedInWorkerid = w.ID
JOIN Roles AS r
ON w.RoleID = r.RoleID
WHERE (r.Descript = 'Hourly')
AND wf.Login >= #StartDate AND wf.Logout <= #EndDate
I've not seen any examples that seemed to fit my requirements, and was hoping

I hope that this is what you are looking for:
DECLARE #StartDate AS DateTime
SET #StartDate = CAST('03/25/2012' AS DATE)
DECLARE #EndDate AS DateTime
SET #EndDate = CAST('03/31/2012' AS DATE)
SELECT
w.Firstname
,w.Lastname
,wf.Login
,wf.logout
,ROUND(CAST(DATEDIFF(MI, wf.Login, wf.Logout) AS DECIMAL)/60,2) AS [Hours]
,w.LunchDeduction AS [Lunch Deduction]
,ROUND(CAST(DATEDIFF(MI, wf.Login, wf.Logout) AS DECIMAL)/60,2)
- CASE
WHEN DATEDIFF(hour, wf.Login, wf.Logout) < wf.MinimumHours THEN
w.LunchDeduction
ELSE
0
END AS [HoursBilled]
FROM Workers AS w
JOIN Workflow AS wf
ON wf.LoggedInWorkerid = w.ID
JOIN Roles AS r
ON w.RoleID = r.RoleID
WHERE (r.Descript = 'Hourly')
AND wf.Login >= #StartDate AND wf.Logout <= #EndDate
There was a comma missing before case statement, and mathematic was a bit strange. It seems to me that you intended to substract w.LunchDeduction from hours billed in case worker put less than wf.MinimumHours into hi/hers job, but instead you used that info as a precision parameter to round function.

Related

Getting totals in SSRS today(), Month, Quarterly and year to date

Data from main table
i have the following SQL query:
SELECT
ISNULL(SUM(intIntrosHot), 0) Hot, ISNULL(SUM(intIntrosCold), 0) Cold,
ISNULL(ISNULL(SUM(intIntrosHot), 0) + ISNULL(SUM(intIntrosCold), 0),0) Total
FROM tblUBMReport
WHERE tblUBMReport.intProp IN 865
---AND dtReport BETWEEN #StartDate AND #EndDate;
but for the life of me, I have no idea how to get or design my table in SSRS for total hot leads for today, total hot leads for the month, total hot leads for this quarter, and total hot leads for this year. I need to have my table look like the picture below any help will be appreciated.
This is an image showing what I'm looking to get as an outcome:
enter image description here
You should be able to get the results desired by grouping your data by date and then filtering the data by the date range.
SELECT dtReport,
ISNULL(SUM(intIntrosHot), 0) Hot, ISNULL(SUM(intIntrosCold), 0) Cold,
ISNULL(ISNULL(SUM(intIntrosHot), 0) + ISNULL(SUM(intIntrosCold), 0),0) Total
FROM tblUBMReport
WHERE tblUBMReport.intProp IN 865
GROUP BY dtReport
Then add the Expressions for each date range and each temp:
CURRENT DATE
=SUM(IIF(Fields!dtReport.Value = TODAY, Fields!Cold.Value, 0))
MTD
=SUM(IIF(Fields!dtReport.Value >= TODAY.AddDays(1 - TODAY.Day) AND Fields!dtReport.Value <= TODAY, Fields!Cold.Value, 0))
QTD
=SUM(IIF(Fields!dtReport.Value >= DateSerial(Today.Year, (Int((Today.Month - 1) / 3) + 1, 1) AND Fields!dtReport.Value <= TODAY,
Fields!Cold.Value,
0)
)
If you hot and cold were on separate lines, it would be easier since the table could be grouped by the Hot/Cold.
I was able to solve my issue and wanted to post it in here so other people who run across the issue can use the solution.
SELECT
'Hot' AS strType,
SUM(CASE WHEN dtReport = #EndDate THEN intIntrosHot ELSE 0 END) AS intDT,
SUM(CASE WHEN dtReport BETWEEN tblDate.dtFirstDayOfMonth AND #EndDate THEN intIntrosHot ELSE 0 END) AS intMTD,
SUM(CASE WHEN dtReport BETWEEN tblDate.dtFirstDayOfQuarter AND #EndDate THEN intIntrosHot ELSE 0 END) AS intQTD,
SUM(CASE WHEN dtReport BETWEEN tblDate.dtFirstDayOfYear AND #EndDate THEN intIntrosHot ELSE 0 END) AS intYTD
FROM
tblUBMReport WITH (NOLOCK)
INNER JOIN tblDate WITH (NOLOCK) ON tblDate.dtDate = #EndDate
WHERE
intProp IN (#Props) AND dtReport BETWEEN #StartDate AND #EndDate
UNION
SELECT
'Cold' AS strType,
SUM(CASE WHEN dtReport = #EndDate THEN intIntrosCold ELSE 0 END) AS intDT,
SUM(CASE WHEN dtReport BETWEEN tblDate.dtFirstDayOfMonth AND #EndDate THEN intIntrosCold ELSE 0 END) AS intMTD,
SUM(CASE WHEN dtReport BETWEEN tblDate.dtFirstDayOfQuarter AND #EndDate THEN intIntrosCold ELSE 0 END) AS intQTD,
SUM(CASE WHEN dtReport BETWEEN tblDate.dtFirstDayOfYear AND #EndDate THEN intIntrosCold ELSE 0 END) AS intYTD
FROM
tblUBMReport WITH (NOLOCK)
INNER JOIN tblDate WITH (NOLOCK) ON tblDate.dtDate = #EndDate
WHERE
intProp IN (#Props) AND dtReport BETWEEN #StartDate AND #EndDate

Mysql if Null or Empty String then Show N/A

Hello I'm new to mysqsl and I'm trying to display N/A if the return data is empty or NULL but my query is unrecognized statement type. What do you think is wrong with my query? wrong placement of code?
CASE when 'Earliest Time Opened' = '' or 'Earliest Time Opened' is 'Null'
then 'N/A'
ELSE
SELECT (date_format(d.date_opened, '%r') as 'Earliest Time Opened'
FROM daily_report d JOIN userinfo ui
ON d.userid= ui.id
WHERE d.date_opened >= date_sub(curdate(), interval 0 day)
AND d.survey_at_what_blh = 'Bagong Silang' AND ui.status='Employee'
ORDER BY d.date_opened DESC
limit 1
END
Use IF with ISNULL here:
SELECT IF(ISNULL(d.date_opened), 'N/A', DATE_FORMAT(d.date_opened, '%r')) AS `Earliest Time Opened`
FROM daily_report d
INNER JOIN userinfo ui ON d.userid = ui.id
WHERE
d.date_opened >= CURDATE() AND
d.survey_at_what_blh = 'Bagong Silang' AND
ui.status = 'Employee'
ORDER BY
d.date_opened DESC
LIMIT 1;
If you really wanted to use a CASE expression, then it would need to appear inside the select clause, something like this:
SELECT CASE WHEN DATE_FORMAT(d.date_opened, '%r') IS NOT NULL
THEN DATE_FORMAT(d.date_opened, '%r')
ELSE 'N/A' END AS `Earliest Time Opened`
But COALESCE is much more terse and appropriate here.

How to query last 2 business days only

I'm running a query that pulls the correct information I'm looking for, but I need it to pull the last 2 business days rather than the last 2 days. This comes into play when it's Monday and my results show information for Monday and Sunday rather than Monday and Friday. How can I change my query to pull in business days only?
USE [LetterGeneration]
SELECT g.LetterGenerationPrintJobId
,CAST(t.[TemplateKey] AS VarChar) AS LetterCode
,convert(char(12),r.CreatedDate,101) AS CreatedDate
,s.LetterGenerationStatusId AS Status
,s.StatusKey AS StatusDesc
,count(g.LetterGenerationId) as LetterCount
,c.BankingDateYorN
FROM [LetterGenerationTemplateRequest] AS r
INNER JOIN [LetterGenerationTemplate] AS t
ON t.[LetterGenerationTemplateId] = r.LetterGenerationTemplateId
INNER JOIN LetterGeneration g
ON g.LetterGenerationTemplateRequestId = r.LetterGenerationTemplateRequestId
INNER JOIN LetterGenerationStatus s
ON g.LetterGenerationStatusId = s.LetterGenerationStatusId
INNER JOIN Enterprise..Calendar C
ON c.BeginDate = g.LetterDate
WHERE ((DATEDIFF(d, r.CreatedDate, GETDATE()) = 0) OR (DATEDIFF(d, r.CreatedDate, GETDATE()) = 1))
--BankingDateYorN = 1
--AND RelativeTimeValue_BusinessDates =-1
AND t.[TemplateKey] NOT LIKE '%PLTV1%'
AND s.LetterGenerationStatusId NOT LIKE '4'
AND s.LetterGenerationStatusId NOT LIKE '16'
AND s.LetterGenerationStatusId NOT LIKE '19'
AND s.LetterGenerationStatusId NOT LIKE '20'
AND s.LetterGenerationStatusId NOT LIKE '38'
GROUP BY r.[LetterGenerationTemplateRequestId]
,r.LetterGenerationTemplateId
,g.Lettergenerationprintjobid
,t.[TemplateKey]
,r.[Loan_no]
,r.CreatedDate
,r.[CreatedBy]
,s.LetterGenerationStatusId
,s.StatusKey
,c.BankingDateYorN
ORDER BY r.CreatedDate DESC
UPDATE: I've recently discovered how to join a calendar table to my current query. The calendar query has a column called BusinessDayYorN with 1's for a business day and 0's for weekends and holidays. I've also updated the old query to now include the join.
select *
from LetterGenerationTemplateRequest
where createddate >= (
getdate() -
case datename(dw,getdate())
when 'Tuesday' then 5
when 'Monday' then 4
else 3
end
)
--and datename(dw,createdDate) not in ('Saturday','Sunday',datename(dw,getdate()))
and datename(dw,createdDate) not in ('Saturday','Sunday')
;
Assuming that you always want to include the last two non-weekend days you can try this:
; with aux as (
select diff = case
when datename(weekday, getdate()) in ('Tuesday', 'Wednesday ', 'Thursday', 'Friday') then 1
else
case datename(weekday, getdate())
when 'Saturday' then 2
when 'Sunday' then 3
when 'Monday' then 4
end
end
)
SELECT --r.[LetterGenerationTemplateRequestId]
--,r.LetterGenerationTemplateId
g.LetterGenerationPrintJobId
,CAST(t.[TemplateKey] AS VarChar) AS LetterCode
,r.[Loan_no]
,convert(char(12),r.CreatedDate,101) AS CreatedDate
-- ,g.ModifiedDate
-- ,convert(varchar(18), g.ModifiedDate - r.CreatedDate, 108) AS TimeSpan
,s.LetterGenerationStatusId AS Status
,s.StatusKey AS StatusDesc
,count(g.LetterGenerationId) as LetterCount
FROM [LetterGenerationTemplateRequest] AS r
INNER JOIN [LetterGenerationTemplate] AS t
ON t.[LetterGenerationTemplateId] = r.LetterGenerationTemplateId
INNER JOIN LetterGeneration g
ON g.LetterGenerationTemplateRequestId = r.LetterGenerationTemplateRequestId
INNER JOIN LetterGenerationStatus s
ON g.LetterGenerationStatusId = s.LetterGenerationStatusId
WHERE
DATEDIFF(day, r.CreatedDate, GETDATE()) <= (select diff from aux)
AND t.[TemplateKey] NOT LIKE '%PLTV1%'
AND s.LetterGenerationStatusId NOT LIKE '4'
AND s.LetterGenerationStatusId NOT LIKE '16'
AND s.LetterGenerationStatusId NOT LIKE '19'
AND s.LetterGenerationStatusId NOT LIKE '20'
AND s.LetterGenerationStatusId NOT LIKE '38'
GROUP BY r.[LetterGenerationTemplateRequestId]
,r.LetterGenerationTemplateId
,g.Lettergenerationprintjobid
,t.[TemplateKey]
,r.[Loan_no]
,r.CreatedDate
-- ,g.ModifiedDate
,r.[CreatedBy]
,s.LetterGenerationStatusId
,s.StatusKey
ORDER BY r.CreatedDate DESC
The CTE aux returns a dataset with only one record and only one field, the value of which is the number of days you need to go back in your WHERE statement.

Struggling to get desired return

I'm relatively new to SQL, but am generally a quick learner and this particular query has stumped me for a few days. Any help would be beyond appreciated at this point.
When I run the below query, I only return rows where there exists a statusdatetime (the agent logged in that day). I need to return a row even when the agent didn't log in but was scheduled. How can I change this query to return a NULL for that. I thought the left join would work.
DECLARE #startDate datetime
DECLARE #endDate datetime
SET #startDate = GETDATE()
SET #endDate = GETDATE()
SET #startDate = CONVERT(DATETIME, CONVERT(varchar(11),#startDate, 111 ) + ' 00:00:00', 111)
SET #endDate = CONVERT(DATETIME, CONVERT(varchar(11),#endDate, 111 ) + ' 23:59:59', 111)
Begin
Create table #boris5table(
Firstname varchar(50),
lastname varchar (50),
username varchar (50),
starttime datetime,
loggedintime datetime,
variation int)
End
Insert into #boris5table (Firstname, lastname, username, starttime, loggedintime, variation)
Select firstname, lastname, userid,
(cast(DATEADD(MINUTE, (-300 +
(select min(startoffset) from [dbo].[IO_ScheduleInterval]
Where activitytypeid = '0000000000000000000004'
and PaidTime = '1'
and f1.agentid = f2.agentid
and ScheduleID = f1.scheduleid)), StartDateTimeUTC) as datetime)),
case when exists (select count(*), statusdatetime from [dbo].[AgentActivityLog] Where StatusDateTime between #startdate and #enddate Group by StatusDateTime) then min(statusdatetime)
Else NULL
End as LoggedInTime,
DATEDIFF(minute, (cast(DATEADD(MINUTE, (-300 +
(select min(startoffset) from [dbo].[IO_ScheduleInterval]
Where activitytypeid = '0000000000000000000004'
and PaidTime = '1'
and f1.agentid = f2.agentid
and ScheduleID = f1.scheduleid)), StartDateTimeUTC) as datetime)),
case when exists (select statusdatetime from [dbo].[AgentActivityLog] Where StatusDateTime between #startdate and #enddate and f3.UserId = f2.UserName) then min(statusdatetime)
Else 'NULL' END)
as 'Variation (minutes)'
From [I3_IC].[dbo].[IO_Schedule] as f1
left join [dbo].[IO_Agent] as f2 on f1.AgentID = f2.AgentID and (CAST(DATEADD(hour, - 5, f1.StartDateTimeUTC) as date)) between #startdate and #enddate
left join [dbo].[Individual] as f4 on f2.UserName = f4.WebLogin and LastName <> '-'
left join [dbo].[AgentActivityLog] as f3 on f2.UserName = f3.UserId and (CAST(DATEADD(hour, -1, f3.StatusDateTime) as date)) between #startdate and #enddate
Group by firstname, lastname, f2.UserName, ScheduleID, f1.AgentID, f2.AgentID, StartDateTimeUTC, f3.UserId
Select *
From #boris5table
drop table #boris5table

Date is not getting set

I have a procedure that should always set a date, but it does not:
CREATE PROCEDURE 'player_extend_membership` (pid INTEGER, daysToAdd INTEGER, OUT result INTEGER)
BEGIN
SELECT PlayerMembershipEndDate INTO #memDate FROM players WHERE players.PlayerID = pid LIMIT 1;
SELECT ROW_COUNT() INTO #num;
IF #num = 0 THEN
SET result = -1;
ELSE
IF #memDate = NULL OR DATE(#memDate) < DATE(NOW()) THEN
SET #finalDate = DATE_ADD(DATE(NOW()), INTERVAL daysToAdd DAY);
ELSE
SET #finalDate = DATE_ADD(DATE(#memDate), INTERVAL daysToAdd DAY);
END IF;
SELECT #finalDate, #memDate;
UPDATE players SET PlayerMembershipEndDate = #finalDate
WHERE players.PlayerID = pid;
SET result = 1;
END IF;
END
When I check the return value, it is 1, therefore the account does exist. It tells me the result of the select query is always that #finalDate is NULL.
However, if ake it out of the IF and just do:
SET #finalDate = DATE_ADD(DATE(NOW()), INTERVAL daysToAdd DAY);
The date is set correctly.
I'm not sire what I am doing wrong.
Thanks
Your procedure seems way too complicated. Perhaps this does what you want:
set #result = -1;
UPDATE players
SET PlayerMembershipEndDate = (case when (#result := 1) is null then NULL
when #memDate IS NULL OR DATE(#memDate) < DATE(NOW())
then DATE_ADD(DATE(NOW()), INTERVAL daysToAdd DAY)
else DATE_ADD(DATE(#memDate), INTERVAL daysToAdd DAY)
end)
WHERE players.PlayerID = pid;
The first condition in the case just sets #result if a row is found. I've left your formulation of DATE(NOW()) even though CURDATE() is more succinct.
I suspect the actual problem with your logic was the = NULL. This always returns "UNKNOWN", which is treated as false. The correct expression is is NULL.