SQL rent due at different frequencies - sql

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

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 create a calculated field with a where clause in the calculation

The image shows the table from this code: select * from PunchClock
where punchmonth = 1 and PunchDay = 1 and PunchYear = 2018
I am trying to calculate the number of hours worked per day in a database. Our table for this has 2 columns that pertain to this. InOut is a column that has either 1 or 0 (1 = punch in, 0 = punch out), and then there is the punchdatetime. How could I use these two fields to calculate how many hours are worked per day.
I have tried to subtract the punch time in from the punch time out but that won't work.
select PunchMonth, PunchDay, PunchYear,
((PunchDateTime where InOut = 0) - (punchdatetime where InOut = 1))
from PunchClock
Error Message: Incorrect syntax near the keyword 'where'.
could be you need case (not where)
select PunchMonth
, PunchDay
, PunchYear
, case INOut = 0 then PunchDateTime else -PunchDateTime end
from PunchClock
I think you want a case expression. Also, because a given row has either an InOut value of 0 or 1 but not both, I think you need aggregation.
So, I'm guessing:
select PunchMonth, PunchDay, PunchYear,
datediff(second, min(case when InOut = 0 then punchdatetime end),
max(case when InOut = 1 then punchdatetime end)
) as seconds_diff
from PunchClock
group by PunchMonth, PunchDay, PunchYear;

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

Sum if date exists for this month

I'am trying to work out the AmountRequested for all completed cases for this month.
I'am using SQL 2008
If there is a date in the column DateCompleted for this month then give me the sum of AmountRequested for those columns
Here is my code it keeps falling over saying "Operand type clash: date is incompatible with int"
SUM(case WHEN CONVERT(DATE,pm.DateCompleted,103)
= MONTH(GETDATE()) AND YEAR(pm.DateCompleted) = YEAR(GETDATE())
THEN pm.AmountRequested
ELSE 0 end) AS [LoanAmount]
CONVERT(DATE,pm.DateCompleted,103) = MONTH(GETDATE())
Here you are trying to compare date with integer so the error.
Ex.
CONVERT(DATE,pm.DateCompleted,103) may return '2016-10-11' and MONTH(GETDATE()) will return 10. You trying to equate '2016-10-11' = 10 so the error is generated
Why not use the same MONTH function for your column also
Sum(CASE
WHEN Month(pm.DateCompleted) = Month(Getdate())
AND Year(pm.DateCompleted) = Year(Getdate()) THEN pm.AmountRequested
ELSE 0
END) AS [LoanAmount]

Display only needed results in SQL

I need a little assistance in finishing this query. Here is what I have so far:
select
(select count(fileName)
from PDFFile
where dateTime > cast(getdate() as date)
and stateId = 17) AS "Files on SFTP"
,
(select count(fileName)
from PDFFile
where dateTime > cast(getdate() as date)
and stateId = 12) AS "Files Pass"
,
((select count(fileName)
from PDFFile
where dateTime > cast(getdate() as date)
and stateId = 17)
-
(select count(fileName)
from PDFFile
where dateTime > cast(getdate() as date)
and stateId = 12)) AS "Diff"
This is going to give me 3 columns of results. First result will be a number, second will be a number and the third will be the diff. There may even be a better way to write this but I'm still a novice. Hint: There is an entry in the DB for each state:
fileName |dateTime | stateID
--------+---------+-----------------+---------
abc.pdf | 2013-12-17 12:03:14.597 | 17
abc.pdf | 2013-12-17 12:06:23.096 | 12
xyz.pdf | 2013-12-17 12:09:16.583 | 17
xyz.pdf | 2013-12-17 12:10:19.823 | 12
Anyways for the finale...
I need to have a 4th column or a separate query (possible to UNION?) that pulls the fileNames based off the results in the diff.
Hypothetically if the diff is 40, the 4th column or separate query should list the 40 names. At times the diff may be negative so again hypothetically speaking if its -40 it should list the 40 names.
Assistance is greatly appreciated. Thank you!
You can greatly simplify your query using conditional aggregation:
select sum(case when dateTime > cast(getdate() as date) and stateId = 17 then 1 else 0
end) as "Files on SFTP",
sum(case when dateTime > cast(getdate() as date) and stateId = 12 then 1 else 0
end) AS "Files Pass",
(sum(case when dateTime > cast(getdate() as date) and stateId = 17 then 1 else 0
end) -
sum(case when dateTime > cast(getdate() as date) and stateId = 12 then 1 else 0
end)
) as diff
from PDFFile;
To get the list of files that are in the first group but not the second requires a bit more logic. The problem is that the unit of aggregation is at the file level.
select PDFFile
from PDFFile
group by PDFFile
having sum(case when dateTime > cast(getdate() as date) and stateId = 17 then 1 else 0
end) > 0 and
sum(case when dateTime > cast(getdate() as date) and stateId = 12 then 1 else 0
end) = 0;
Each part of the having clause counts the number of rows -- for each file -- that match the two conditions. You want at least one row that matches the first condition (hence > 0) and no rows that match the second (= 0).
This type of "combine row data into one column" question comes up quite a lot on Stack Overflow and although it has its place it's often easier and more efficient to solve the problem in another way.
For example, it's a lot easier to ask SQL to "give me all the filenames where stateid = 17", return them to your app and then get the app to display them. It may also be that your user doesn't want to see them until there is a particular summary line that is of interest to them that they need to drill down into further. Think of email as an example - you may only need to look at the 30 character subject line and know you don't need to download the 1Mb email body.
For your first question though there is a lot easier (and more efficient) way to write your query. Note that this example is untested
select
sum(case when stateId = 17 then 1 else 0 end) as "Files on SFTP",
sum(case when stateId = 12 then 1 else 0 end) as "Files Pass",
sum(case when stateId = 17 then 1 else 0 end) -
sum(case when stateId = 12 then 1 else 0 end) as "Diff",
from
PdfFile
where
datetime > getdate()
I'm using CASE here to prevent having to do three separate sub-queries. Sub-queries are inefficient. CASE isn't great but it's faster than sub-queries. I've also placed your datetime check at the bottom of the query as a WHERE as it was common to each of your checks.