How to use case to construct a conditional update - sql

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()))

Related

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

ms sql 2012 case syntax

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

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

SQL rent due at different frequencies

I have a FirstRentPaymentDate date field and a RentFrequency field with four possible values (Week,Fortnight,Month,Year).
Time on the date field is irrelevant but are all set to 12:00:00.
How could I work out if FirstRentPaymentDate for a frequency equals today using a SQL query?
One way of doing this that doesn't require a lastpaid date:
select
firstdate
,frequency
from sampledata
WHERE
CASE WHEN frequency = 'week' THEN DATEDIFF(DD,firstdate,getdate()) % 7
WHEN frequency = 'fortnight' THEN DATEDIFF(DD,firstdate,getdate()) % 14
WHEN frequency = 'month' AND Day(firstdate) = Day(getdate()) THEN 0
WHEN frequency = 'year' AND Day(firstdate) = Day(getdate())
AND Month(firstdate) = Month(getdate()) THEN 0
END = 0

Conditional updates on sql query

In my code I have written an update query according to the date. That means, I have created an application for payroll, in that monthly they want to add month leave as two. If it is a new joinee that will separate two. This is the process I have done through my code. Now they want to change the model, that is, if the new joinee date of join has been greater than 15 days it should add one day leave. Please help me to do this. And this is my code befor I used:
UPDATE tbl_emploeedetails
SET elbal = elbal - 2
WHERE employeestatus = 'L'
AND ( Month(doj) = Month(Getdate()) - 1
AND Year(doj) = Year(Getdate())
AND Day(doj) > 25 )
OR ( Month(doj) = Month(Getdate())
AND Year(doj) = Year(Getdate()) )
and this is month leave add query :
update tbl_emploeedetails
set elbal = elbal + 2 where employeestatus = 'L'
You can use something like this
UPDATE YourTable
SET UpdateColumn =
(CASE
WHEN <Condition1> THEN <Expression1>
WHEN <Condition2> THEN <Expression2>
ELSE <Expression3>
END)
Example:
UPDATE YourTable
SET UpdateColumn =
(CASE
WHEN A>B THEN D * 2
WHEN A>C THEN D * 3
ELSE D * 4
END)