ms sql 2012 case syntax - sql

I have table survey_status_history which is having columns caseId, strsurveystatus, dtcreated.
I want to fetch record from table for all status but when status = 'pending', for this case query should return record for last five days only.
Below is my query.
select *
from survey_status_history ssh
where nisactive = 1
and case when ssh.strsurveystatus = 'pending'
then ssh.dtcreated > DATEADD(DAY, 5 , GETDATE())
end
But I am getting error near >
Kindly suggest the changes in query.
Thanks in advance.

SQL Server doesn't understand a boolean type. I would recommend writing this without the case:
select *
from survey_status_history ssh
where nisactive = 1 and
(ssh.strsurveystatus <> 'pending' or
ssh.dtcreated > DATEADD(DAY, 5 , GETDATE())
);
This assumes that strsurveystatus is never NULL. If it is NULL the logic is slightly more complicated.

Hope, this suits your requirement.
SELECT *
FROM SURVEY_STATUS_HISTORY SSH
WHERE NISACTIVE = 1 AND
(SSH.STRSURVEYSTATUS <> 'PENDING' -- if not pending
OR(SSH.STRSURVEYSTATUS = 'PENDING' AND SSH.DTCREATED >= DATEADD(DAY, -5 , GETDATE()))) -- if pending and last 5 days

Related

How to use case to construct a conditional update

I have to write an update query. If the special_member account is not cancelled then in the where clause I have to use this condition by adding a grace period of 15 days to the expiry date and compare it today's date:
Convert(date,MEMBER_EXPIRY_DATE + 15) >= Convert(date,GETDATE())
If the membership is cancelled then I have to compare the actual expiry date with today's date. This is my full query:
UPDATE SPECIAL_MEMBER SET SAVINGS_PERCENT = 10, ORDER_COUNT = 1
WHERE SPECIAL_MEMBER = '4382' AND CASE WHEN (CANCELLED = 0) THEN
Convert(date,MEMBER_EXPIRY_DATE + 15) >= Convert(date,GETDATE())
ELSE (Convert(date,MEMBER_EXPIRY_DATE) >= Convert(date,GETDATE())) END
When I execute it I am getting:
Incorrect syntax near '>'.
Its a case expression, not a statement, as as such it can only return a value i.e. cannot contain any conditions. Just move the value you are comparing to outside the case e.g.
UPDATE SPECIAL_MEMBER SET
SAVINGS_PERCENT = 10
, ORDER_COUNT = 1
WHERE SPECIAL_MEMBER = '4382'
AND CASE WHEN CANCELLED = 0
THEN CONVERT(DATE,DATEADD(DAY,15,MEMBER_EXPIRY_DATE))
ELSE CONVERT(DATE,MEMBER_EXPIRY_DATE) END >= CONVERT(DATE,GETDATE());
That however is not sargable i.e. cannot make use of any indexes on MEMBER_EXPIRY_DATE so I would recommend switching the logic around to
UPDATE SPECIAL_MEMBER SET
SAVINGS_PERCENT = 10
, ORDER_COUNT = 1
WHERE SPECIAL_MEMBER = '4382'
AND MEMBER_EXPIRY_DATE >= CONVERT(DATE,DATEADD(DAY,CASE WHEN CANCELLED = 0 THEN -15 ELSE 0 END,GETDATE()))
Notes:
Dates don't naturally add, use the dateadd function.
There is nothing dynamic about this - dynamic SQL is something quite different
Using a good layout and consistent casing makes a big difference in being able to read your SQL
You can ignore the CASE and use like below:
UPDATE SPECIAL_MEMBER
SET SAVINGS_PERCENT = 10
, ORDER_COUNT = 1
WHERE SPECIAL_MEMBER = '4382'
AND ( CANCELLED = 0 AND DATEADD(dd,15,CONVERT(DATE, MEMBER_EXPIRY_DATE)) >= CONVERT(DATE,GETDATE())
OR CANCELLED != 0 AND CONVERT(DATE,MEMBER_EXPIRY_DATE) >= CONVERT(DATE,GETDATE()))

How to write a T-SQL query which can return 0 rows as part of a case statement

I am trying to write a query which checks how many records arrived in the last x days so that I can send out an alert if no new records have arrived in that window.
To that end I want a query which will check the table and return either 1 row stating no files were detected if there is a problem or no rows if everything is ok. The reason I want there to be no rows is because the downstream program will treat any returned rows as an error having been detected and alert accordingly.
select 'Null check' as id,
case when
count(*) > 0 then NULL
else 'No files detected' end as Message
from TABLE where LASTUPDATEDATE > dateadd(d, -1, getdate())
This query works if an error is detected but not in the correct case as it still returns a row. How can I rewrite it so that it doesn't return anything? Thanks!
For performance reasons, I would recommend writing this as:
select 'Null check' as id, 'No files detected' as Message
from (select top (1) t.*
from table t
where lastupdatedate > dateadd(day, -1, getdate())
) t
having count(*) = 0;
This saves SQL Server from actually having to count a bunch of rows if when things are fine.
Seems to be a task for NOT EXISTS:
select 'Null check' as id, 'No files detected' as Message
where not exists
(
select *
from tab
where lastupdatedate > dateadd(day, -1, getdate())
)
The trick is to use having count(*) = 0
select 'Null check' as id, 'No files detected' as Message
from TABLE
where LASTUPDATEDATE > dateadd(d, -1, getdate())
having count(*) = 0
Demo
SQL Fiddle - count() = 0
SQL Fiddle - count() > 0
You can accomplish this with a CASE and subquery:
SELECT [Message] =
CASE
WHEN COALESCE(SELECT COUNT(*) FROM [TABLE] WHERE [LASTUPDATEDATE] > DATEADD(d, -1, GETDATE())), 0) > 0
THEN 'No files detected'
ELSE NULL
END ;

CASE in WHERE Clause

Below is my current SQL Server 2012 query. Basically I want the information from the last business day, but on Monday, I want it to pull Friday's info instead of Sunday. This is what I have so far in my query but it won't accept it.
USE [LetterGeneration]
SELECT
g.LetterGenerationPrintJobId,
CONVERT(CHAR(12), r.CreatedDate, 101) AS CreatedDate,
YEAR(r.CreatedDate) AS Year,
MONTH(r.CreatedDate) AS Month,
DAY(r.CreatedDate) AS Day,
CASE
WHEN DATEPART(dw, r.CreatedDate) = 1
THEN 1
WHEN DATEPART(dw, r.CreatedDate) = 7
THEN 1
ElSE 0
END AS Weekend,
s.LetterGenerationStatusId AS Status,
COUNT(g.LetterGenerationId) AS LetterCount,
SUM(g.LetterPageCount) AS PageCount,
t.IsLitigationCoverLetterAllowed,
CASE
WHEN g.CarrierTrackingNumber LIKE '%1ZE%'
THEN 1
WHEN g.CarrierTrackingNumber LIKE '921489%'
THEN 2
WHEN g.CarrierTrackingNumber LIKE '917190%'
THEN 2
ELSE 3
END AS CarrierType
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
(CASE
WHEN (DATENAME(dw,GETDATE()) = 'Monday')
THEN (DATEDIFF(d, r.CreatedDate, GETDATE()) = 3)
ELSE (DATEDIFF(d, r.CreatedDate, GETDATE()) = 1)
END)
AND t.[TemplateKey] NOT LIKE '%PLTV1%'
AND s.LetterGenerationStatusId = 19
ORDER BY
r.CreatedDate DESC, g.LetterGenerationPrintJobId DESC
What am I missing or misunderstanding about my WHERE clause in order to make it work in the way I'm thinking?
Thanks
Maybe convert to a regular AND/OR?
WHERE (
((DATENAME(dw,GETDATE()) = 'Monday') AND (DATEDIFF(d, r.CreatedDate, GETDATE()) = 3))
OR
(DATEDIFF(d, r.CreatedDate, GETDATE()) = 1)
)
....
What am I missing or misunderstanding about my WHERE clause in order to make it work in the way I'm thinking?
Though you haven't given the error message you're getting, I'm sure it's syntax related because you're putting the test INSIDE the result of the case, not outside it
You're writing:
WHERE CASE WHEN it_is_monday THEN data_date = friday ELSE data_date = yesterday END
You should be writing:
WHERE data_date = CASE WHEN it_is_monday THEN friday ELSE yesterday END
Essentially: you're not supposed to use case/when in a where clause to do your "column = something" comparison and return you true or false, you're supposed to use it to just return the "something" you compare against "column" else in order to get your true or false
The other answers focus on "giving you a working solution"; this answer focuses on telling you what was going wrong with your thought processes re your original query
Here's a simpler example:
--wrong syntax to search a table full of cats (4 legs) and people (2 legs)
WHERE CASE WHEN animal_type = 'cat' THEN legs = 4 ELSE legs = 2 END
--right syntax
WHERE limbs = CASE WHEN animal_type = 'cat' THEN 4 ELSE 2 END
Ignoring holidays for a second, and assuming you have at least one record for every date, something like this should work.
where cast(createdDate as date) =
(select max(createdDate )
from table
where createdDate < cast(getDate() as date
and dateName(dw, createdDate in ('Monday' etc)
)
In order to maintain SARGability(able to do a seek against an index) you want to make sure the table columns in the predicate aren't included in any functions.
The following should work and maintain SARGability...
WHERE
r.CreatedDate = CASE
WHEN DATEPART(dw, getdate) = 2
THEN DATEADD(dd, -3, CAST(GETDATE() AS DATE))
ELSE CAST(GETDATE() AS DATE)
END
HTH,
Jason

sql query to get dIvided group

Table - Activity(jobid,duedate,status)
status can be either 'Complete' or "NotComplete".
I need a single sql query to get
how many jobs are complete
how many jobs are not-complete having duedate is greater than current date
how many jobs are not-complete having duedate is less than current date
Can anyone please help me with this? Result should have only 3 rows and two columns.
Edit : I am looking for best query, perhaps with any inbuilt function/keyword which performs task in single line query. Not sure if it is possible.
Something like this:
SELECT Count(jobid) AS total,
'Completed'
FROM activity
GROUP BY status
HAVING status = 'Complete'
UNION
SELECT Count(jobid) AS total,
'Completed Due in past.'
FROM activity
WHERE duedate >= Getdate()
GROUP BY status
HAVING status = 'Complete'
UNION
SELECT Count(jobid) AS total,
'Completed Due in past.'
FROM activity
WHERE duedate < Getdate()
GROUP BY status
HAVING status = 'Complete'
Try case :
select
case when status='Complete' then '1'
when status='NotComplete' and duedate >= getdate() then '2'
else '3' end,
count(jobid)
from Activity
group by
case when status='Complete' then '1'
when status='NotComplete' and duedate >= getdate() then '2'
else '3' end
Try This:-
SELECT COUNT(JOBID) Completed Jobs, STATUS
FROM Activity
WHERE STATUS = "Complete"
GROUP BY STATUS
UNION
SELECT COUNT(JOBID) Completed Jobs, STATUS
FROM Activity
WHERE duedate > GETDATE() AND STATUS = "NotComplete"
GROUP BY STATUS
UNION
SELECT COUNT(JOBID) Completed Jobs, STATUS
FROM Activity
WHERE duedate < GETDATE() AND STATUS = "NotComplete"
GROUP BY STATUS;
This might be helpful to you.
Select sum( case when status = 'Complete' then 1 else 0 end ) as completedJobs,
Sum ( case when status ='NotCompleted' and duedate > getdate() then 1 else 0 end ) as notcompletedinDuedate,
Sum ( case when status ='NotCompleted' and duedate < getdate() then 1 else 0 end ) as notcompletedJobs
From Activity
Everyone, Thanks for your reply. I was looking for best query with 2 columns. This is my solution. If anyone have short/good version query, please suggest.
;with cte as (
select
case
when stat = 'N' and duedate > GETDATE() then 'NG'
when stat = 'N' and duedate < GETDATE() then 'NL'
else stat
end As S, duedate from activity)
select S,COUNT(*) from CTE group by (S)

SQL conditional WHERE simplification

I currently have a statement in my WHERE clause like this:
AND ((#includeExpired = 0 AND lic.[DateExpiresUtc] > GETDATE())
OR
(#includeExpired = 1 AND lic.[DateExpiresUtc] <> GETDATE())
)
Which just looks ugly, I've tried just including a simpler version of the statement like:
(#includeExpired = 0 AND lic.[DateExpiresUtc] > GETDATE())
But when #includeExpired is 1 it all fails to select anything.
Is there a better way of doing this?
According to your variabel name #includeExpired, which implies that this variable decides about additionally including expired records in the result set, the check in the second part, lic.[DateExpiresUtc] <> GETDATE(), is not necessary and the other check in the first part is not necessary.
Try this:
AND (lic.[DateExpiresUtc] > GETDATE()) OR (#includeExpired = 1)
Just one idea.
(CASE
WHEN #includeExpired = 1 THEN 1
WHEN #includeExpired = 0 AND lic.[DateExpiresUtc] > GETUTCDATE() THEN 1
ELSE 0 END) = 1