SQL date selection as NULL, After, Before, Between - sql

Requirement: select by date as After, Before, Between or all if null
I'm using SQL Server 2008
This is my attempt but I'm getting syntax errors on code that is valid used outside of the case.
Is there a better method?
using case what is the correct syntax?
declare #StartDate datetime;
declare #EndDate datetime;
SET #EndDate = GETDATE();
SET #StartDate = DATEADD(year, -2, GETDATE());
select *
from ArCustomer
where CAST(Customer as int) > 1000
AND
CASE WHEN #StartDate IS NOT NULL AND #EndDate IS NOT NULL THEN
ArCustomer.DateLastSale BETWEEN #StartDate AND #EndDate
WHEN #StartDate IS NULL AND #EndDate IS NOT NULL THEN
ArCustomer.DateLastSale < #EndDate
WHEN #StartDate IS NOT NULL AND #EndDate IS NULL THEN
ArCustomer.DateLastSale > #StartDate
END;

Alternately, you could not restrict by the date parameter if it is NULL:
SELECT *
FROM ArCustomer ac
WHERE
CAST(ac.Customer as int) > 1000
AND (ac.DateLastSale >= #StartDate OR #StartDate IS NULL)
AND (ac.DateLastSale <= #EndDate OR #EndDate IS NULL)
Or... you can handle the NULL by treating it as the low-end or high-end date:
SELECT *
FROM ArCustomer ac
WHERE
CAST(ac.Customer as int) > 1000
AND ac.DateLastSale BETWEEN ISNULL(#StartDate, '1900-01-01')
AND ISNULL(#EndDate, '9999-12-31')
EDIT:
There could be a difference in the execution plan between these two approaches, so you might try both methods and see if one out-performs the other...

WHERE CAST(Customer as int) > 1000 AND
(#StartDate IS NULL OR #StartDate <= ArCustomer.DateLastSale) AND
(#EndDate IS NULL OR ArCustomer.DateLastSale <= #EndDate)

Please note that the below query should have * avoided and the specific column names should be mentioned.
declare #StartDate datetime;
declare #EndDate datetime;
SET #EndDate = GETDATE();
SET #StartDate = DATEADD(year, -2, GETDATE());
Declare #SQL Varchar(1000)
Set #SQL = 'select ColumnName
from ArCustomer
where CAST(Customer as int) > 1000
AND'
if(#StartDate IS NOT NULL AND #EndDate IS NOT NULL)
Begin
Set #SQL = #SQL + ' ArCustomer.DateLastSale BETWEEN ''' + Convert(varchar, #StartDate) +
''' AND ''' + Convert(varchar, #EndDate) + ''''
End
else if(#StartDate IS NULL AND #EndDate IS NOT NULL)
Begin
Set #SQL = #SQL + ' ArCustomer.DateLastSale < ''' + Convert(varchar, #EndDate) + ''''
End
else
Set #SQL = #SQL + ' ArCustomer.DateLastSale > ''' + Convert(varchar, #StartDate) + ''''
exec(#SQL)
Considered all cases.

Related

Varchar and Date Incompatible SQL

I have written the below SQL and trying to do it using variables.
--Select DB
USE [gkretail_master]
--Declare Varibles
DECLARE #StartDate DATE;
DECLARE #EndDate DATE;
DECLARE #SQL VARCHAR(8000);
--Set Variables
SET #StartDate = '2018-05-23 00:00:00.000';
SET #EndDate = '2018-05-23 23:59:00.000'
SET #SQL =
'SELECT
RETAIL_STORE_NUMBER AS ''Store Number'',
DESCRIPTION_1 AS ''Store Name'',
CAST(SUM(BRUTTOGES) AS DECIMAL(18,2)) AS ''Total Taken''
FROM [GKRETAIL_MASTER].[GK_BONKOPF]
JOIN [gkretail_master].[GK_STORE_DATA] ON [GK_BONKOPF].[ID_BSNGP] = [GK_STORE_DATA].[ID_BSNGP]
WHERE
AKTDAT > '+ #StartDate +'
AND
AKTDAT < '+ #EndDate +'
GROUP BY [GK_BONKOPF].[ID_BSNGP], DESCRIPTION_1, RETAIL_STORE_NUMBER';
EXECUTE(#SQL);
It however returns the error:
The data types varchar and date are incompatible in the add operator.
I have done some googling and tried to resolve it using both CAST and convert but it flags up more errors.
Any ideas?
Exactly. That is one important reason why you should pass parameters using sp_executesql:
SET #SQL =
'SELECT
RETAIL_STORE_NUMBER AS ''Store Number'',
DESCRIPTION_1 AS ''Store Name'',
CAST(SUM(BRUTTOGES) AS DECIMAL(18,2)) AS ''Total Taken''
FROM [GKRETAIL_MASTER].[GK_BONKOPF]
JOIN [gkretail_master].[GK_STORE_DATA] ON [GK_BONKOPF].[ID_BSNGP] = [GK_STORE_DATA].[ID_BSNGP]
WHERE
AKTDAT > #StartDate
AND
AKTDAT < #EndDate
GROUP BY [GK_BONKOPF].[ID_BSNGP], DESCRIPTION_1, RETAIL_STORE_NUMBER';
EXEC sp_executesql #SQL,
N'#StartDate date, #EndDate date',
#StartDate = #StartDate, #EndDate = #EndDate;

Conditionally setting a variable in SQL

I'm trying to do this:
If the Day parameter is the current day, then set #EndDate to be yesterday instead
If the Day parameter is in the future, set #EndDate to yesterday.
I've tried a few different approaches including two down below. I'm fairly new to programming so odds are I'm missing something fairly simple. Basically, I am trying to set #EndDate conditionally, depending on what #Day is set to be.
DECLARE #Day DATETIME
SET #Day = '09/2/17 12:50'
SET #Day = DATEADD(dd, DATEDIFF(dd, 0, #Day), 0)
DECLARE #Enddate DATETIME
SET #Enddate = CASE #Day
WHEN #Day < GETDATE() THEN GETDATE() - 1
END
--SET #Enddate = #Day
-- WHERE #Day < GETDATE()
--SET #Enddate = GETDATE()-1
-- WHERE#Day >= GETDATE()
Thanks
You are mixing the two possible ways to write a case expression...
You can either use
CASE #day
WHEN GETDATE() THEN 'x'
WHEN DATEADD(DAY, 1, GETDATE() THEN 'y'
END
or then you can use:
CASE
WHEN #day = GETDATE() THEN 'x'
WHEN #day > GETDATE() THEN 'y'
END
This is the correct way:
SET #Enddate = CASE
WHEN #Day < GETDATE()
THEN DATEADD(DAY, -1, GETDATE())
ELSE GETDATE()
END
For clarification, variable #yesterday added as DATE without time
Declare #Day datetime
Set #Day = '09/02/17 12:50'
SET #Day = DATEADD(dd, DATEDIFF(dd, 0, #Day), 0)
Declare #Enddate Datetime
Declare #yesterday as date
SET #yesterday=dateadd(day,-1,getdate())
Set #Enddate = Case
When #day< #yesterday Then #day else #yesterday End
Any values older than yesterday remains as is, other case sets yesterday

Date Range Based on Today

I am trying to write a stored procedure that will be called by an automated report on the 1st, 8th, 15th, and 22nd of each month.
Below I have the code I am currently trying to use however I keep getting the error Explicit conversion from data type int to date is not allowed. on the line for #StartDate if ran on the 1st. However I have tried commenting out that section and I just get the same error but then for the next #StartDate.
I need #StartDate and #EndDate to be able to change based on which day of the month the report is currently being ran.
On the 1st it would need to be ran from the 21st of the
previous month to the end of the previous month.
On the 8th it would need to be 1st of the current month to the 7th.
On the 15th it would need to be 8th of the current month to the 14th.
On the 22nd it would need to be 15th of the current month to the 21st.
Declare #RunDate date
Declare #StartDate Date
Declare #EndDate Date
Set #RunDate = '3/1/2017'
If (Day(#RunDate) = 1)
Begin
Set #StartDate = Convert(Date,(Month(DATEADD(d,-1,#Rundate)) + '/21/' + Case When Month(#Rundate) = '1' Then Year(#RunDate) Else Year(DATEADD(yy,-1,#Rundate)) End),101)
Set #EndDate = Convert(date,DATEADD(ms,-3,DATEADD(mm,0,DATEADD(mm,DATEDIFF(mm,0,#Rundate),0))),101)
End
Else
IF (Day(#RunDate) = 8)
Begin
Set #StartDate = Convert(Date,(Month(#Rundate) + '/1/' + Year(#RunDate)),101)
Set #EndDate = Convert(Date,(Month(#Rundate) + '/7/' + Year(#RunDate)),101)
End
Else
If (Day(#Rundate) = 15)
Begin
Set #StartDate = Convert(Date,(Month(#Rundate) + '/8/' + Year(#RunDate)),101)
Set #EndDate = Convert(Date,(Month(#Rundate) + '/14/' + Year(#RunDate)),101)
End
Else
If (Day(#Rundate) = 22)
Begin
Set #StartDate = Convert(Date,(Month(#Rundate) + '/15/' + Year(#RunDate)),101)
Set #EndDate = Convert(Date,(Month(#Rundate) + '/21/' + Year(#RunDate)),101)
End
I am using SQL Server 2012 back end with SSMS 2016 front end. If that helps.
You can simplify all of that down to:
Declare #RunDate date, #StartDate date, #EndDate date;
Set #RunDate = '20170301';
If (Day(#RunDate) = 1)
Begin;
Set #StartDate = dateadd(day,20,dateadd(month, datediff(month, 0, #RunDate)-1, 0))
Set #EndDate = dateadd(day,-1,dateadd(month, datediff(month, 0, #RunDate), 0))
End;
Else
If (Day(#RunDate) in (8,15,22))
Begin;
Set #StartDate = dateadd(day,Day(#RunDate)-8,dateadd(month, datediff(month, 0, #RunDate), 0))
Set #EndDate = dateadd(day,Day(#RunDate)-2,dateadd(month, datediff(month, 0, #RunDate), 0))
End;
Alternative using case, but doesn't verify for the day() in 8,15,22:
Declare #RunDate date, #StartDate date, #EndDate date;
Set #RunDate = '20170328';
set #StartDate = case day(#RunDate)
when 1 then dateadd(day,20,dateadd(month, datediff(month, 0, #RunDate)-1, 0))
else dateadd(day,Day(#RunDate)-8,dateadd(month, datediff(month, 0, #RunDate), 0))
end;
set #EndDate = case day(#RunDate)
when 1 then dateadd(day,-1,dateadd(month, datediff(month, 0, #RunDate), 0))
else dateadd(day,Day(#RunDate)-2,dateadd(month, datediff(month, 0, #RunDate), 0))
end;
rextester demo of both: http://rextester.com/CCUFI85069
Try changing the code to set the dates like this...
SET #StartDate = CONVERT(DATE,
CONCAT(MONTH(DATEADD(d, -1, #Rundate)),
'/21/',
IIF(MONTH(#Rundate) = '1', YEAR(#RunDate), YEAR(DATEADD(yy, -1, #Rundate)))) , 101)
The full code will look like this...
Declare #RunDate date
Declare #StartDate Date
Declare #EndDate Date
Set #RunDate = '3/1/2017'
If (Day(#RunDate) = 1)
Begin
Set #StartDate = CONVERT(DATE, CONCAT(MONTH(DATEADD(d, -1, #Rundate)), '/21/',IIF(MONTH(#Rundate) = '1', YEAR(#RunDate), YEAR(DATEADD(yy, -1, #Rundate)))) , 101)
Set #EndDate = Convert(date,DATEADD(ms,-3,DATEADD(mm,0,DATEADD(mm,DATEDIFF(mm,0,#Rundate),0))),101)
End
Else
IF (Day(#RunDate) = 8)
Begin
Set #StartDate = Convert(Date, CONCAT(Month(#Rundate) , '/1/' , Year(#RunDate)) ,101)
Set #EndDate = Convert(Date, CONCAT(Month(#Rundate) , '/7/' , Year(#RunDate)) ,101)
End
Else
If (Day(#Rundate) = 15)
Begin
Set #StartDate = Convert(Date, CONCAT(Month(#Rundate) , '/8/' , Year(#RunDate)) ,101)
Set #EndDate = Convert(Date, CONCAT(Month(#Rundate) , '/14/' , Year(#RunDate)) ,101)
End
Else
If (Day(#Rundate) = 22)
Begin
Set #StartDate = Convert(Date, CONCAT(Month(#Rundate) , '/15/' , Year(#RunDate)) ,101)
Set #EndDate = Convert(Date, CONCAT(Month(#Rundate) , '/21/' , Year(#RunDate)) ,101)
END
SELECT #StartDate, #EndDate
You could even hide the repetitive code and create a simple function...
CREATE FUNCTION [dbo].[GetDateBasedOnStringNumber] (#num NVARCHAR(20), #RunDate DATE)
RETURNS DATE
WITH SCHEMABINDING AS
BEGIN
DECLARE #retDate DATE
SELECT #retDate = Convert(Date, CONCAT(Month(#RunDate) , #num , Year(#RunDate)) ,101)
RETURN #retDate ;
END;
and then use this pattern instead...
SELECT #StartDate = dbo.GetDateBasedOnStringNumber('/1/', #RunDate)
SELECT #EndDate = dbo.GetDateBasedOnStringNumber('/7/', #RunDate)
The error is because you are trying to add integer and varchar values together. Using this line as an example:
Set #StartDate = Convert(Date,(Month(DATEADD(d,-1,#Rundate)) + '/21/' + Case When Month(#Rundate) = '1' Then Year(#RunDate) Else Year(DATEADD(yy,-1,#Rundate)) End),101)
If you break down the parts of your calculation you have the month integer value, a day varchar value and a year integer value. If you try to concatenate these you get the error message:
Msg 245, Level 16, State 1, Line 9 Conversion failed when converting
the varchar value '/21/' to data type int.
You could cast the integer values to varchar and it would work.
It is recommended to use the built-in date functions than using concatenation so you could achieve the same result like so:
DECLARE
#RunDate DATE = '20170101'
, #StartDate DATE
, #EndDate DATE
IF DATEPART(DAY, #RunDate) = 1
SELECT
#StartDate = DATEADD(DAY, -(DATEPART(DAY, DATEADD(DAY, -1, #RunDate)) - 20), #RunDate)
, #EndDate = DATEADD(DAY, -1, #RunDate)
SELECT
#StartDate
, #EndDate

How to print a week in date in SQL

I use sql server.
what I've been doing is this:
LEFT(yearmonth,4) + RIGHT( '0' + CONVERT(VARCHAR, DATEPART(WK, yearmonthdate)), 2)
yearmonth = '201601'
and
yearmonthdate = '20160101' through '20160131'
which prints out like this:
201601
201602
but I want to print out like the following:
20160101-20160102
20160103-20160109
respectively.
How do I accomplish that?
I've on google but I couldn't get to print out like that.
Thank you in advance.
DECLARE #Table TABLE (Col1 INT, Col2 DATETIME)
DECLARE #StartDT DATETIME
DECLARE #tempDT DATETIME
DECLARE #EndDT DATETIME
SET #StartDT = DATEFROMPARTS(YEAR(getdate()),MONTH(getdate()),1)
SET #EndDT = EOMONTH (#StartDT)
set #tempDT=#StartDT
WHILE #StartDT < #EndDT
BEGIN
PRINT
CONVERT(VARCHAR,cast(#tempDT as date))
+ ' - ' +
convert(VARCHAR,cast(DATEADD(dd, 7-(DATEPART(dw, #StartDT)), #StartDT) as date))
SET #StartDT = DATEADD(dd, 7-(DATEPART(dw, #StartDT)), #StartDT)
SET #tempDT = DATEADD(dd,1,#StartDT)
SET #StartDT = DATEADD(WEEK,1,#StartDT)
END
PRINT
CONVERT(VARCHAR,cast(#tempDT as date))
+ ' - ' +
convert(VARCHAR,cast(#EndDT as date))

Can some please help me and show me what I'm doing wrong

CREATE TABLE DateRange
([Date] DATETIME, IsFutureOrPast BIT)
DECLARE #Date AS DATETIME
SET #DATE ='2014-01-01 00:00:00.000'
WHILE #DATE <='2014-12-31 00:00:00.000'
BEGIN
INSERT INTO DateRange ([DATE])
VALUES (#DATE)
SET #Date = #Date + 1
END
--Case Statement to check values and enter flag
DECLARE #CurrentDate AS DATETIME = GETDATE()
UPDATE
DateRange
SET [DATE] =
CASE
WHEN #CurrentDate <= [DATE] THEN 0
ELSE 1
END AS IsPastOrFuture
FROM DateRange
WHERE [Date] IN ( 0, 1)
You're trying to set the DATE field when you should be setting the IsFutureOrPast field:
UPDATE
DateRange
SET [IsFutureOrPast] =
CASE WHEN #CurrentDate <= [DATE] THEN 0
ELSE 1
END
But you could also combine the two statements:
INSERT INTO DateRange ([DATE], [IsFutureOrPast])
VALUES (
#DATE,
CASE WHEN GETDATE() <= #DATE THEN 0 ELSE 1 END
)
SET #Date = #Date + 1
Try this:
DECLARE #DateRange TABLE
([Date] DATETIME, IsFutureOrPast BIT)
DECLARE #Date AS DATETIME
SET #DATE ='2014-01-01 00:00:00.000'
WHILE #DATE <='2014-12-31 00:00:00.000'
BEGIN
INSERT INTO #DateRange ([DATE])
VALUES (#DATE)
SET #Date = #Date + 1
END
--Case Statement to check values and enter flag
DECLARE #CurrentDate AS DATETIME = GETDATE()
UPDATE
#DateRange
SET IsFutureOrPast =
CASE
WHEN #CurrentDate <= [DATE] THEN 0
ELSE 1
END
FROM #DateRange
SELECT * FROM #DateRange
I think you are trying to SET the IsPastOrFuture column
DECLARE #CurrentDate AS DATETIME = GETDATE()
UPDATE
DateRange
SET
IsPastOrFuture = CASE
WHEN #CurrentDate <= [DATE] THEN 0
ELSE 1
END