How to query all rows that are due the next business day? - sql

If it helps, I'm using BytePro which I believe is using T-SQL based on the statement they've generated.
I'm having an issue where when I try retrieving data, I need to switch based on the day of the week. (current day being today's date using GetDate()).
M-T statement:
convert(varchar(10), [Status.SchedFundingDate], 112) <= convert(varchar(10), getdate() + 1, 112)
F statement:
convert(varchar(10), [Status.SchedFundingDate], 112) <= convert(varchar(10), getdate() + 3, 112)
I'd like to combine the two to automate the switch but I get a problem with
CAST(CASE
WHEN DATENAME(DW, GETDATE()) = 'Friday'
AND [Status.SchedFundingDate] <= GETDATE() + 3
THEN 1
WHEN [Status.SchedFundingDate] <= GETDATE() + 1
THEN 1
ELSE 0
END AS BIT)
I get an error:
An expression of non-boolean type specified in a context where a condition is expected, near 'AND'

this is the right syntax :
CAST(CASE WHEN DATENAME(DW, GETDATE()) = 'Friday'
AND [Status].[SchedFundingDate] <= DATEADD(DAY, 3 , GETDATE())
THEN 1
WHEN [Status].[SchedFundingDate] <= DATEADD(DAY, 1 , GETDATE())
THEN 1
ELSE 0
END AS BIT)
db<>fiddle here

Related

simplify a SQL case statement in a case expression

How would I simplify this case statement in T-SQL? It provides the desired result, but it's very unwieldy and hard to read. I have to use the inner case statement to convert a Julian date (aka 6 digit number) into a regular date format.
Basically i'm doing a datediff( getdate(), case statement). Getdate() just returns the time now (ie. 2/27/2020) and the case statement converts a julian date (ie. 123456) into a normal date (ie, 1/1/2020).
Here's the expect output if the query was ran today on Feb 27.
Select CASE
WHEN Datediff(day, Getdate(), CASE
WHEN a.wadpl = 0
THEN NULL
ELSE Dateadd(d, Substring(Cast(wadpl AS VARCHAR(6)), 4, 3) - 1, CONVERT(DATETIME, CASE
WHEN LEFT(Cast(wadpl AS VARCHAR(6)), 1) = '1'
THEN '20'
ELSE '21'
END + Substring(Cast(wadpl AS VARCHAR(6)), 2, 2) + '-01-01'))
END) < 0
THEN 'Overdue Now'
WHEN Datediff(day, Getdate(), CASE
WHEN a.wadpl = 0
THEN NULL
ELSE Dateadd(d, Substring(Cast(wadpl AS VARCHAR(6)), 4, 3) - 1, CONVERT(DATETIME, CASE
WHEN LEFT(Cast(wadpl AS VARCHAR(6)), 1) = '1'
THEN '20'
ELSE '21'
END + Substring(Cast(wadpl AS VARCHAR(6)), 2, 2) + '-01-01'))
END) <= 30
THEN 'Coming due in 01-30 days'
ELSE 'Not Overdue'
END [Overdue Status]
FROM Table_X
Here is a easy one to understand, assuming a.wadpl is an integer:
SELECT CASE
WHEN DATEDIFF(DAY, GETDATE(), DATEADD(DAY, a.wadpl % 1000, DATEADD(YEAR,a.wadpl / 1000,'1899-12-31'))) <0 THEN 'Overdue now'
WHEN DATEDIFF(DAY, GETDATE(), DATEADD(DAY, a.wadpl % 1000, DATEADD(YEAR,a.wadpl / 1000,'1899-12-31'))) <= 30 THEN 'Coming due in 01-30 days'
ELSE 'Not Overdue'
END [Overdue Status]
FROM Table_X
or you can simplify by using a subquery (or you can use a WITH):
SELECT CASE
WHEN Age <0 THEN 'Overdue now'
WHEN Age <= 30 THEN 'Coming due in 01-30 days'
ELSE 'Not Overdue'
END [Overdue Status]
FROM (
SELECT DATEDIFF(DAY,GETDATE(),
DATEADD(DAY,wadpl%1000,DATEADD(YEAR,wadpl/1000,'1899-12-31'))) Age, *
FROM Table_X) a
This will of course cause you to do this arithmetic for each row, and you can't easily use any indexes. If you were asking about aggregates, then I would suggest doing the opposite, and pre-calculating the dates and use those in your query instead. You might also want to consider putting a persisted computed column on table_x:
ALTER TABLE TABLE_X
ADD wadpl_dt AS
(DATEADD(DAY,wadpl%1000,DATEADD(YEAR,wadpl/1000,'1899-12-31'))) PERSISTED;
Now you can just refer to table_x.wadpl_dt whenever you want the datetime, and your query would become:
SELECT CASE
WHEN Age <0 THEN 'Overdue now'
WHEN Age <= 30 THEN 'Coming due in 01-30 days'
ELSE 'Not Overdue'
END [Overdue Status]
FROM (
SELECT DATEDIFF(DAY,GETDATE(), wadpl_dt) Age, *
FROM Table_X) a
Here is the easy way to convert a date to what you refer to as the julian date:
SELECT (DATEPART(YEAR,GETDATE())-1900) * 1000 + DATEPART(DAYOFYEAR, GETDATE())
And this is how you can use it:
DECLARE #overdue int;
DECLARE #next30 int;
SET #overdue = (SELECT (DATEPART(YEAR,GETDATE())-1900) * 1000 + DATEPART(DAYOFYEAR, GETDATE()));
SET #next30 = (SELECT (DATEPART(YEAR,GETDATE()+30)-1900) * 1000 + DATEPART(DAYOFYEAR, GETDATE()+30));
SELECT CASE
WHEN wadpl < #overdue THEN 'Overdue now'
WHEN wadpl <= #next30 THEN 'Coming due in 01-30 days'
ELSE 'Not Overdue'
END [Overdue Status]
FROM Table_X

SQL: Pull previous day's activity (include weekend on Mondays)

I'm trying to return data from the previous day, except for on Monday I want to return data from the previous 3 days. The below seems logical to me, though I'm getting the error of Incorrect syntax near '='.
Any idea what I'm missing?
*Dates stored in datetime hence the CONVERT functions.
WHERE
CASE WHEN DATEPART(DW,GETDATE()) IN ('1')
THEN (CONVERT(DATE,EV.EVENT_DATE) = CONVERT(DATE,DATEADD(D,-3,GETDATE())))
ELSE (CONVERT(DATE,EV.EVENT_DATE) = CONVERT(DATE,DATEADD(D,-1,GETDATE())))
END
SQL Server does not support boolean expressions like this.
You can express this without the case, which is generally preferable:
WHERE ( DATEPART(WEEKDAY, GETDATE()) = 1 AND CONVERT(DATE, EV.EVENT_DATE) = CONVERT(DATE, DATEADD(DAY, -3, GETDATE()))
) OR
( DATEPART(WEEKDAY, GETDATE()) <> 1 AND CONVERT(DATE, EV.EVENT_DATE) = CONVERT(DATE, DATEADD(DAY, -1, GETDATE()))
)
EDIT:
If you want the weekend dates, then use inequalities. Assuming event_dates are not in the future:
You'll notice that I spelled out the date parts. I find this a better practice than trying to remember/figure out what a particular abbreviation might mean.
WHERE ( DATEPART(WEEKDAY, GETDATE()) = 1 AND CONVERT(DATE, EV.EVENT_DATE) >= CONVERT(DATE, DATEADD(DAY, -3, GETDATE()))
) OR
( DATEPART(WEEKDAY, GETDATE()) <> 1 AND CONVERT(DATE, EV.EVENT_DATE) >= CONVERT(DATE, DATEADD(DAY, -1, GETDATE()))
)

SQL WHERE depending on day of week

I have a requirement to check records up to differing dates, depending on which day of the week it is currently.
On a Friday I need for it to look at the entire next week, until Sunday after next. On any other day it should check the current week, up until the coming Sunday.
I have the below currently but it's not working due to syntax error. Is it possible to do a CASE WHEN inside a WHERE clause?
WHERE
T0.[Status] IN ('R','P')
AND
CASE
WHEN DATEPART(weekday,GETDATE()) = '5'
THEN T0.[DueDate] >= GETDATE() AND <= DATEADD(day, 15 - DATEPART(weekday, GetDate()), GetDate())
WHEN DATEPART(weekday, GETDATE()) != '5'
THEN T0.[DueDate] >= GETDATE() AND <= DATEADD(DAY ,8- DATEPART(weekday, GETDATE()), GETDATE())
END
It's much easier to create this logic with a series of logical or and and operators:
WHERE
T0.[Status] IN ('R','P') AND
((DATEPART(weekday,GETDATE()) = '5' AND
T0.[DueDate] >= GETDATE() AND
T0.[DueDate] <= DATEADD(day, 15 - DATEPART(weekday, GetDate()), GetDate())) OR
(DATEPART(weekday,GETDATE()) != '5' AND
T0.[DueDate] >= GETDATE() AND
T0.[DueDate] <= DATEADD(DAY ,8- DATEPART(weekday,GETDATE()),GETDATE())
)
Your syntax is wrong, you are using a condition evaluation in the THEN clause instead of an assignemnet
WHEN DATEPART(weekday,GETDATE()) = '5' THEN Your_column1 ELSE your_column2 END
......
or a inner case
CASE
WHEN DATEPART(weekday,GETDATE()) = '5' THEN
CASE WHEN T0.[DueDate] >= GETDATE()
AND <= DATEADD(day, 15 - DATEPART(weekday, GetDate()), GetDate())
THEN Your_column1 ELSE your_column2
END
END
......

COUNT total by weekly and monthly SQL

I have a table in which I have to count total rows assigned to each USER by daily, weekly and monthly.
Table BooksIssued
BOOKID ISSUEDUSER DATE
1 A 20160708
2 A 20160709
3 A 20160708
4 A 20150102
5 B 20160709
6 C 20160708
7 C 20160708
Now I have to COUNT daily, weekly and monthly books issued to each user
Daily is today (20160709)
Weekly is Sunday through Saturday
Monthly is whole month
The result should be
ISSUEDUSER DAILYBOOKS WEEKLYBOOKS MONTHLYBOOKS
A 1 3 3
B 1 1 1
C 0 2 2
I have done this SQL for daily issued
SELECT ISSUEDUSER, COUNT(BOOKID) AS DAILYBOOKS
FROM BOOKSISSUED
WHERE DATE = CONVERT(VARCHAR(11), SYSDATETIME(), 112)
GROUP BY ISSUEDUSER
Can someone please help me write a combined SQL for all three ?
Thanks
Aiden
you might need to add a WHERE clause to only retrieve current month's records
SELECT ISSUEDUSER,
SUM(CASE WHEN DATE = DATEADD(DAY, DATEDIFF(DAY, 0, SYSDATETIME()), 0))
THEN 1 ELSE 0 END) AS DAILYBOOKS,
SUM(CASE WHEN DATE >= DATEADD(WEEK, DATEDIFF(WEEK, 0, SYSDATETIME()), 0)
AND DATE < DATEADD(WEEK, DATEDIFF(WEEK, 0, SYSDATETIME()) + 1, 0)
THEN 1 ELSE 0 END) AS WEEKLYBOOKS,
COUNT(*) AS MONTHLYBOOKS
FROM BOOKSISSUED
WHERE DATE >= DATEADD(MONTH, DATEDIFF(MONTH, 0, SYSDATETIME()), 0)
AND DATE < DATEADD(MONTH, DATEDIFF(MONTH, 0, SYSDATETIME()) + 1, 0)
GROUP BY ISSUEDUSER
EDIT : for [DATE] column is INT
SELECT ISSUEDUSER,
SUM(CASE WHEN DATE = CONVERT(INT, CONVERT(VARCHAR(8), SYSDATETIME(), 112))
THEN 1 ELSE 0 END) AS DAILYBOOKS,
SUM(CASE WHEN DATE >= CONVERT(INT, CONVERT(VARCHAR(8), DATEADD(WEEK, DATEDIFF(WEEK, 0, SYSDATETIME()), 0), 112))
AND DATE < CONVERT(INT, CONVERT(VARCHAR(8), DATEADD(WEEK, DATEDIFF(WEEK, 0, SYSDATETIME()) + 1, 0), 112))
THEN 1 ELSE 0 END) AS WEEKLYBOOKS,
COUNT(*) AS MONTHLYBOOKS
FROM BOOKSISSUED
WHERE DATE >= CONVERT(INT, CONVERT(VARCHAR(6), SYSDATETIME(), 112) + '01')
AND DATE < CONVERT(INT, CONVERT(VARCHAR(6), DATEADD(MONTH, 1, SYSDATETIME()), 112) + '01')
GROUP BY ISSUEDUSER
You should consider investing in a legitimate Date_Time table.
It makes comparing the official beginning and ending of the weeks MUCH easier and practical. And hey, you might even be able to use indexing!
However, there is another way. AS you shall see, DATEPART returns the ISO Month and Week we are looking for.
So provided our year is right, we now know where our boundaries are and can easily use an IIF(<boolean_expression>, <true_expression>, <false_expression>) statement inside of a COUNT(<column>). COUNT ignores NULLs, so we set TRUE to 1 and FALSE to NULL. :D
-- Note, I changed the column [Date] to [Dates]
DECLARE #Date INT
SET #Date = CAST(CAST(SYSDATETIME() AS VARCHAR(4) ) + '0101' AS INT)
SELECT ISSUEDUSER--DATEPART(YYYY, CAST(Dates AS VARCHAR(10) ) )
, COUNT( IIF(DATEDIFF(MM, CAST(Dates AS VARCHAR(10) ), GETDATE() ) = 0
, 1
, NULL) ) AS MONTHS
, COUNT( IIF(DATEDIFF(WW, CAST(Dates AS VARCHAR(10) ), GETDATE() ) = 0
, 1
, NULL) ) AS Weeks
, COUNT( IIF(DATEDIFF(DD, CAST(Dates AS VARCHAR(10) ), GETDATE() ) = 0
, 1
, NULL) ) AS Days
FROM #BookReport
WHERE DATES >= #Date
GROUP BY ISSUEDUSER
--results
ISSUEDUSER MONTHS Weeks Days
A 3 3 1
B 1 1 1
C 2 2 0
Note that you can expand the allowable date difference by adjusting the boolean statement! No extra coding required.
Also note that your examples actually only have one date that is not of the same Month, Week, or Day (within one day), although in my example I required Days to be of the same day as the query to make it look a bit different.
Cool Observations:
DATE by definition has no formatting and DATEPART can guess from a well-formed Datetime string, so there was no reason to double cast your Date column. However, if your pattern changes, you may need to add a CONVERT.
DATEPART gives you the standard (ISO) Month and Week recognized, which means no Date_Time table required here. :)
DATEDIFF is the magic here, and makes your Boolean statement REALLY easy to work with.
Pretty slick, no?
MSDN's page on DATEPART is worth a quick glance.

Obtaining columns values only if date > today

I have a query where i need to get values in 4 columns but only if the date is greater than today from a 5th column. I have tried the following but it doesn't seem to be working.
Select
(case when clientplans.END_DATE < convert(date,getdate(,101) then '') else insplans.Desc_upper as PLAN NAME,
(case when clientplans.END_DATE < convert(date,getdate(,112) then '') else insplans.ID_NO,
(case when clientplans.END_DATE < convert(date,getdate(,112) then '') else insplans.cert_NO,
I have converted the date on the end date as follows:
convert (varchar,clientplans.END_DATE,112) as POLICY_EXP_DATE,
does it matter that I do the conversion of the end date later in the query? the clientplans.end_date has to be inserted into the results in a certain order which happens to be after the description, id and cert number. Thanks for any help.
Perhaps something like this does what you want:
Select (case when cp.END_DATE > cast(getdate() as date) then insplans.Desc_upper end) as PLAN_NAME,
(case when cp.END_DATE > cast(getdate() as date) then insplans.ID_NO end) as ID_NO,
(case when cp.END_DATE > cast(getdate() as date) then insplans.cert_NO END) as cert_NO
from clientplans cp . . .
Note the following:
This table uses table aliases (cp for clientplans), so the query is easier to write and to read.
It uses cast() to a date to just get the date.
Non-matching rows are given a NULL value instead of ''. That usually makes more sense.
EDIT:
Of course, you can use '', if you like:
Select (case when cp.END_DATE > cast(getdate() as date) then insplans.Desc_upper else '' end) as PLAN_NAME,
(case when cp.END_DATE > cast(getdate() as date) then insplans.ID_NO else '' end) as ID_NO,
(case when cp.END_DATE > cast(getdate() as date) then insplans.cert_NO else '' end) as cert_NO,
(case when cp.END_DATE > cast(getdate() as date)
then convert(varchar(255), cp.StartDate, 121) else ''
end) as StartDate
from clientplans cp . . .
Use this to get the start of today: DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)
For example:
SELECT DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)
And for yours...
Select
(case when clientplans.END_DATE > DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) then '') else insplans.Desc_upper as PLAN NAME,
(case when clientplans.END_DATE > DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) then '') else insplans.ID_NO,
(case when clientplans.END_DATE > DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) then '') else insplans.cert_NO,
i think proper casting is required So I Used Here CAST(Field as DATE) and
in Your Query getdate(,101) is wrong syntax
Select
(case when CAST(clientplans.END_DATE as date) < CAST(getdate() as date) then '')
else insplans.Desc_upper as PLAN NAME,
(case when CAST(clientplans.END_DATE as date) < CAST(getdate() as date) then '')
else insplans.ID_NO,
(case when CAST(clientplans.END_DATE as date) < CAST(getdate() as date) then '')
else insplans.cert_NO
You can use cursor on the 5th column
and check #cursor_date> is greater than today.
Only then will get the rest of the 4 columns.