If condition with CTE in sql - sql

I am trying to Create a view where i need to put condition on year and I am trying below code but I get an error. Can someone please suggest if its possible . And the output which is required I have to use CTE only.
Error is as below : incorrect Syntax near ‘if’
Code is as below :
Declare #year varchar(20)
Set #year = ‘2022’;
With CTE as
(
If #year = ‘2022’
Begin
(
Select
#year ,
Prev_date = (select DATEADD(month, -1,GETDATE()))
)
End;
Else
Begin
(
Select #year,
Prev_date= (select DATEADD(month, -2,GETDATE()))
)
End;
)
Select *
From CTE

I'm not entirely sure what you want to achieve with your cte, but concerning the condition, you can try to put the following into your view / query / whatever:
Declare #year varchar(20)
Set #year = '2022';
SELECT [year] = #year, [prev_date] = DATEADD(month, -1 * CASE WHEN #year = '2022' THEN 1 ELSE 2 END, GETDATE())

IF, BEGIN and END are related to the procedural code, and cannot be used in this context.
Your code, without further specification, can be replaced with the following:
DECLARE #Year varchar(20);
SET #Year = '2022';
WITH CTE AS
(
SELECT Year = #year,
PrevDate = DATEADD(month, -1,GETDATE())
)
SELECT *
FROM CTE;
A note and a piece of advice: it looks (am I wrong?) that you are at the beginning of the learning. Try to keep coding guidelines for SQL Server, please. I have made some quick improvements. An example link to follow: https://blog.sqlauthority.com/2008/09/25/sql-server-guidelines-and-coding-standards/

You can use simple effective query rather than going for CTE which should be used for complex queries.
Declare #year varchar(20) Set #year = '2023';
select #year [Year], prev_date = case when #year='2022' then (Select DATEADD(month, -1,GETDATE())) else DATEADD(month, -2,GETDATE()) end

You have not give the error and what database you are using.
I suppose you sql should be syntax error, please try this
Declare #year varchar(20)
Set #year = ‘2022’
With CTE as
(
If #year = ‘2022’
Begin
{
Select
#year ,
(select DATEADD(month, -1,GETDATE())) as previous_date
}
END;
)
Select *
From CTE
BEGIN ... END; must use with {..} in the case use have multiple statments in between.
Hope this help.

Related

RUN Query based on a given condition

Hi Guys i want to run this query based on condition following condition. if parameter date is less than 01/01/16 it should run the first CTE else the 2nd CTE thanks
DECLARE #Date AS DATET
SET #Date = '2015-10-31'
;WITH OLDVTE AS (SELECT
SalesID,
City,
Amount,
SalesDate
FROM INFO.SALESOLD
),
NEWVTE AS (
SalesID,
City,
Amount,
SalesDate
FROM INFO.SALESNEW
)
SELECT
CASE WHEN GETDATE() <= #Date THEN
(SELECT * FROM OLDVTE)
ELSE
(SELECT * FROM NEWVTE)
END AS DD
You might try something like this:
DECLARE #Date AS DATE = {d'2015-10-31'}
DECLARE #CurrentDateTime DATETIME = GETDATE();
SELECT
SalesID,
City,
Amount,
SalesDate
FROM INFO.SALESOLD
WHERE #CurrentDateTime <= #Date
UNION ALL
SELECT
SalesID,
City,
Amount,
SalesDate
FROM INFO.SALESNEW
WHERE #CurrentDateTime > #Date
The UNION ALL will return both results in one. But there will be only one of the selects returning rows actually...
Hint
I actually doubt, that your filter against GETDATE() would work as you expect it...
You could try with IF ELSE like below..
DECLARE #Date AS DATETIME
SET #Date = '2015-10-31'
If GETDATE() <= #Date--will this clause work..
select * FROM INFO.SALESOLD
Else
select * FROM INFO.SALEnew
You could also join the two tables if they contain any common field and pass date

Inserting weekends into SQL Server table

I'm trying to insert yearly weekend details such as date, dayName into a SQL Server table using the following stored procedure
alter procedure usp_AddOfficeHolidays
#paramName NVARCHAR(max)
as
begin
DECLARE #Year AS INT,
#FirstDateOfYear DATETIME,
#LastDateOfYear DATETIME
-- You can change #year to any year you desire
SELECT #year = 2016
SELECT #FirstDateOfYear = DATEADD(yyyy, #Year - 1900, 0)
SELECT #LastDateOfYear = DATEADD(yyyy, #Year - 1900 + 1, 0)
-- Creating Query to Prepare Year Data
--declare dayN varchar(max)
if (select COUNT(*) from tblWeekSettings) < 1
begin
;WITH cte AS
(
SELECT
1 AS DayID,
#FirstDateOfYear AS FromDate,
DATENAME(dw, #FirstDateOfYear) AS Dayname
UNION ALL
SELECT
cte.DayID + 1 AS DayID,
DATEADD(d, 1 ,cte.FromDate),
DATENAME(dw, DATEADD(d, 1 ,cte.FromDate)) AS Dayname
FROM cte
WHERE DATEADD(d, 1, cte.FromDate) < #LastDateOfYear
)
SELECT FromDate AS Date, Dayname
FROM CTE
WHERE DayName IN (SELECT Param FROM dbo.fn_MVParam(#paramName,','))
OPTION (MaxRecursion 370)
end
else
begin
Select 'Exists'
end
end
and executing it using
exec usp_AddOfficeHolidays 'Saturday,Sunday'
which returns the following result
This works perfectly fine, BUT I have been unable to add/insert these details into the following table
I face the following error when I try to access the WEEKEND details by its alias CTE
The statement terminated. The maximum recursion 100 has been exhausted
before statement completion
Although I've added the clause
OPTION (MaxRecursion 370)
suggested by these links which I found on stack overflow
The maximum recursion 100 has been exhausted before statement completion
The statement terminated. The maximum recursion 100 has been exhausted before statement completion
EDIT
Basically i face the specified error when i try something like this
alter procedure usp_AddOfficeHolidays
#paramName NVARCHAR(max)
as
begin
----------------------------------------------------------
DECLARE #Year AS INT,
#FirstDateOfYear DATETIME,
#LastDateOfYear DATETIME
-- You can change #year to any year you desire
SELECT #year = 2016
SELECT #FirstDateOfYear = DATEADD(yyyy, #Year - 1900, 0)
SELECT #LastDateOfYear = DATEADD(yyyy, #Year - 1900 + 1, 0)
-- Creating Query to Prepare Year Data
--declare dayN varchar(max)
if (select COUNT(*) from tblWeekSettings) < 1
begin
;WITH cte AS (
SELECT 1 AS DayID,
#FirstDateOfYear AS FromDate,
DATENAME(dw, #FirstDateOfYear) AS Dayname
UNION ALL
SELECT cte.DayID + 1 AS DayID,
DATEADD(d, 1 ,cte.FromDate),
DATENAME(dw, DATEADD(d, 1 ,cte.FromDate)) AS Dayname
FROM cte
WHERE DATEADD(d,1,cte.FromDate) < #LastDateOfYear
)
SELECT FromDate AS Date, Dayname
FROM CTE
WHERE DayName IN(SELECT Param FROM dbo.fn_MVParam(#paramName,','))
insert into tblWeekSettings(DayNo,WeekDayName,Dates)
values('',Dayname,Date)
OPTION (MaxRecursion 370)
end
else
begin
Select 'Exists'
end
--select cte
-----------------------------------------------------------
end
Any sort of help here would really be appreciated! I just need to insert the data in my the specified table!
Thank you!
That's the error:
SELECT FromDate AS Date, Dayname
FROM CTE
WHERE DayName IN(SELECT Param FROM dbo.fn_MVParam(#paramName,','))
I split this code to make you understand what code actually is working in this case:
insert into tblWeekSettings(DayNo,WeekDayName,Dates)
values('',Dayname,Date)
OPTION (MaxRecursion 370)
OPTION (MAX RECURSION) now belongs to single insert statement. Which is standalone, totally not related to CTE.
You actually need this, I suppose:
;with CTE (...)
insert into tblWeekSettings(DayNo,WeekDayName,Dates)
SELECT FromDate AS Date, Dayname
FROM CTE
WHERE DayName IN(SELECT Param FROM dbo.fn_MVParam(#paramName,','))
OPTION (MaxRecursion 370)
but there are three columns in target table whilst your select has only two columns. So you'll have to update your select.
Some tips about INSERT-SELECT:
http://www.w3schools.com/sql/sql_insert_into_select.asp
this code:
insert into tblWeekSettings(DayNo,WeekDayName,Dates)
values('',Dayname,Date)
does not have any source for inserting. This is not valid code - you don't have here any Dayname,Date variables - they are not even referenced with # as variables. It's totally not valid code.
For anyone who face the following issues
Getting Weeked details i.e. DayName, Date
Inserting into a Table
This stored procedure would do the trick.
alter procedure usp_AddOfficeHolidays
#paramName NVARCHAR(max)
as
begin
----------------------------------------------------------
DECLARE #Year AS INT,
#FirstDateOfYear DATETIME,
#LastDateOfYear DATETIME
-- You can change #year to any year you desire
SELECT #year = 2016
SELECT #FirstDateOfYear = DATEADD(yyyy, #Year - 1900, 0)
SELECT #LastDateOfYear = DATEADD(yyyy, #Year - 1900 + 1, 0)
-- Creating Query to Prepare Year Data
--declare dayN varchar(max)
if (select COUNT(*) from tblWeekSettings) < 1
begin
;WITH cte AS (
SELECT 1 AS DayID,
#FirstDateOfYear AS FromDate,
DATENAME(dw, #FirstDateOfYear) AS Dayname
UNION ALL
SELECT cte.DayID + 1 AS DayID,
DATEADD(d, 1 ,cte.FromDate),
DATENAME(dw, DATEADD(d, 1 ,cte.FromDate)) AS Dayname
FROM cte
WHERE DATEADD(d,1,cte.FromDate) < #LastDateOfYear
)
insert into tblWeekSettings(DayNo,Dates,WeekDayName)
SELECT '',FromDate AS Date, Dayname
FROM CTE WHERE DayName IN(SELECT Param FROM dbo.fn_MVParam(#paramName,','))
OPTION (MaxRecursion 30000)
end
else
begin
Select 'Exists'
end
--select cte
-----------------------------------------------------------
end
Plus this article could really be helpful.
http://www.w3schools.com/sql/sql_insert_into_select.asp
Try this, I hope this is useful for you.
alter procedure usp_AddOfficeHolidays
#paramName NVARCHAR(max)
as
begin
----------------------------------------------------------
DECLARE #Year AS INT,#DayNo as int=1,
#FirstDateOfYear DATETIME,
#LastDateOfYear DATETIME
-- You can change #year to any year you desire
SELECT #year = 2016
SELECT #FirstDateOfYear = DATEADD(yyyy, #Year - 1900, 0)
SELECT #LastDateOfYear = DATEADD(yyyy, #Year - 1900 + 1, 0)
Select getdate() DateOfYear into #tbl where 1=0
-- Creating Query to Prepare Year Data
--declare dayN varchar(max)
if (select COUNT(*) from tblWeekSettings) < 1
begin
while (#FirstDateOfYear< #LastDateOfYear)
begin
Insert Into #tbl (DayNo,DateOfYear) values (#DayNo,#FirstDateOfYear)
set #FirstDateOfYear+=1
set #DayNo+=1;
End
Insert Into tblWeekSettings (DayNo,WeekDayName,Dates)
SELECT DayNo,DATENAME(dw, DateOfYear) Name,DateOfYear AS Date
FROM #tbl
WHERE DATENAME(dw, DateOfYear) IN(SELECT Param FROM dbo.fn_MVParam(#paramName,','))
end
else
begin
Select 'Exists'
end
--select cte
-----------------------------------------------------------
end

How to get date difference between two dates in same year with one date is from an input date not from the year

Well this is my case: I have an input date X (dd-mm-yyyy), and I want to count the number of days between it with the year part is changed into current year and today's date in SQL. I t comes with the following condition, after the year is changed temporarily: (Here's my current idea of the logic)
- If date X is earlier than today, then difference = datediff(X,now), with the X year is current year
- If date X is later than today, then difference = datediff(X,now), with the X year is one year before
Sample case:
1st case: The input date is 6-6-1990. Today (automatically generated) is 22-8-2011. Then the difference will be = datediff(6-6-2011,22-08-2011)
2nd case: The input date is 10-10-1990. Today (automatically generated) is 22-8-2011. Then the difference will be = datediff(10-10-2010,22-08-2011)
Any idea how to do this in SQL (in SQL Server)? Or is there any other more simple alternatives for this problem? I'd also like this to be done in the query and not using a stored procedure or function
Sorry if there's already a similar question, I just don't know the exact keyword for this problem :( if there's a question like this previously, feel free to direct me there.
Thanks in advance
Here is the implementation (if I understood the logic you need correctly):
USE YourDbName
GO
CREATE FUNCTION YearPartDiff (#date datetime)
RETURNS int
AS
BEGIN
DECLARE #dateCurrentYear datetime
SET #dateCurrentYear = DATEADD(year, YEAR(GETDATE()) - YEAR(#date), #date)
DECLARE #result int
IF #dateCurrentYear < GETDATE()
SET #result = ABS(DATEDIFF(day, #dateCurrentYear, GETDATE()))
ELSE
SET #result = ABS(DATEDIFF(day, DATEADD(year, -1, #dateCurrentYear), GETDATE()))
RETURN(#result)
END
GO
And the example of usage:
USE YourDbName
GO
DECLARE #someDate datetime
SET #someDate = '2011-06-06'
SELECT dbo.YearPartDiff(#someDate) /*returns 77*/
SET #someDate = '2010-10-10'
SELECT dbo.YearPartDiff(#someDate) /*returns 316*/
Basically, #Andrei's solution, but in a single statement:
SELECT
DayDiff = DATEDIFF(
DAY,
DATEADD(YEAR, CASE WHEN LastOcc > GETDATE() THEN -1 ELSE 0 END, LastOcc),
GETDATE()
)
FROM (
SELECT LastOcc = DATEADD(YEAR, YEAR(GETDATE()) - YEAR(#InputDate), #InputDate)
) s
This seems to do the job
SELECT DATEDIFF(DAY, CONVERT(DATETIME, N'2011-06-06'), CONVERT(DATETIME, N'2011-08-22'))
So the basic syntax is
SELECT DATEDIFF(DAY, CONVERT(DATETIME, N'yyyy-mm-dd'), CONVERT(DATETIME, N'yyyy-mm-dd '))
Alternatively, you can use GETDATE() instead of the string for today's date
I have used "SELECT DATEDIFF( D, "+myDate+", GETDATE())" in my code, on SQL Server 2005. It works for me. The value myDate of course would be the DateTime input value.
you should try this query:
create table #T (inp_date datetime)
insert #T values ('06-06-1990')
insert #T values ('08-22-1990')
insert #T values ('10-10-1990')
--select * from #T
select inp_date, GETDATE(),
CASE
WHEN DATEADD(yy,DATEDIFF(yy,inp_date,GETDATE()),inp_date) <= GETDATE()
THEN DATEDIFF(dd,DATEADD(yy,DATEDIFF(yy,inp_date,GETDATE()),inp_date),GETDATE())
ELSE DATEDIFF(dd,DATEADD(yy,DATEDIFF(yy,inp_date,GETDATE())-1,inp_date),GETDATE())
END
from #T

SQL first of every month

Supposing that I wanted to write table valued function in SQL that returns a table with the first day of every month between the argument dates, what is the simplest way to do this?
For example fnFirstOfMonths('10/31/10', '2/17/11') would return a one-column table with 11/1/10, 12/1/10, 1/1/11, and 2/1/11 as the elements.
My first instinct is just to use a while loop and repeatedly insert first days of months until I get to before the start date. It seems like there should be a more elegant way to do this though.
Thanks for any help you can provide.
Something like this would work without being inside a function:
DECLARE #LowerDate DATE
SET #LowerDate = GETDATE()
DECLARE #UpperLimit DATE
SET #UpperLimit = '20111231'
;WITH Firsts AS
(
SELECT
DATEADD(DAY, -1 * DAY(#LowerDate) + 1, #LowerDate) AS 'FirstOfMonth'
UNION ALL
SELECT
DATEADD(MONTH, 1, f.FirstOfMonth) AS 'FirstOfMonth'
FROM
Firsts f
WHERE
DATEADD(MONTH, 1, f.FirstOfMonth) <= #UpperLimit
)
SELECT *
FROM Firsts
It uses a thing called CTE (Common Table Expression) - available in SQL Server 2005 and up and other database systems.
In this case, I start the recursive CTE by determining the first of the month for the #LowerDate date specified, and then I iterate adding one month to the previous first of month, until the upper limit is reached.
Or if you want to package it up in a stored function, you can do so, too:
CREATE FUNCTION dbo.GetFirstOfMonth(#LowerLimit DATE, #UpperLimit DATE)
RETURNS TABLE
AS
RETURN
WITH Firsts AS
(
SELECT
DATEADD(DAY, -1 * DAY(#LowerLimit) + 1, #LowerLimit) AS 'FirstOfMonth'
UNION ALL
SELECT
DATEADD(MONTH, 1, f.FirstOfMonth) AS 'FirstOfMonth'
FROM
Firsts f
WHERE
DATEADD(MONTH, 1, f.FirstOfMonth) <= #UpperLimit
)
SELECT * FROM Firsts
and then call it like this:
SELECT * FROM dbo.GetFirstOfMonth('20100522', '20100831')
to get an output like this:
FirstOfMonth
2010-05-01
2010-06-01
2010-07-01
2010-08-01
PS: by using the DATE datatype - which is present in SQL Server 2008 and newer - I fixed the two "bugs" that Richard commented about. If you're on SQL Server 2005, you'll have to use DATETIME instead - and deal with the fact you're getting a time portion, too.
create function dbo.fnFirstOfMonths(#d1 datetime, #d2 datetime)
returns table as return
select dateadd(m,datediff(m,0,#d1)+v.number,0) as FirstDay
from master..spt_values v
where v.type='P' and v.number between 0 and datediff(m, #d1, #d2)
and dateadd(m,datediff(m,0,#d1)+v.number,0) between #d1 and #d2
GO
Notes
master..spt_values is a source for general purpose sequence numbers in SQL Server
dateadd(m, datediff(m is a technique for working out the first day of month for any date
+v.number is used to increase it by one month each time
0 and datediff(m, #d1, #d2) this condition gives us all the numbers we need to generate a first-of-month date for each month between #d1 and #d2, inclusive of both months
and dateadd(m,datediff(m,0,#d1)+v.number,0) between #d1 and #d2 the final filter to verify that the first-of-month date generated is between #d1 and #d2
Performance comparison against marc_s's code
Summary
8220 ms (CTE)
4173 ms (master..spt_values)
Test
declare #t table (dt datetime)
declare #d datetime
declare #i int
set nocount on
set #d = GETDATE()
set #i = 0
while #i < 10000
begin
insert #t select * from dbo.getfirstofmonth('20090102', '20100506')
delete #t
set #i = #i + 1
end
print datediff(ms, #d, getdate())
set #d = GETDATE()
set #i = 0
while #i < 10000
begin
insert #t select * from dbo.fnfirstofmonths('20090102', '20100506')
delete #t
set #i = #i + 1
end
print datediff(ms, #d, getdate())
Performante
It will loop just between the months involved (4 times in the example):
set dateformat mdy;
declare #date1 smalldatetime,#date2 smalldatetime,#i int
set #date1= '10-31-2010'
set #date2= '02-17-2011'
set #i=1
while(#i<=DATEDIFF(mm,#date1,#date2))
begin
select convert(smalldatetime,CONVERT(varchar(6),DATEADD(mm,#i,#date1),112)+'01',112)
set #i=#i+1
end
I realize this isn't a function, but I'm going to throw this into the mix anyway.
select cal_date from calendar
where day_of_month = 1
and cal_date between '2011-01-01' and '2012-01-01'
This calendar table runs on a PostgreSQL server at work. I'll port it to SQL Server tonight, and run some speed comparisons. (Why? Because this stuff is fun, that's why.)
Just in case anybody is still reading this ...
I cannot imaging that any of the aforementioned functions is faster than this:
declare #DatFirst date = '20101031', #DatLast date = '21110217';
declare #DatFirstOfFirstMonth date = dateadd(day,1-day(#DatFirst),#DatFirst);
select DatFirstOfMonth = dateadd(month,n,#DatFirstOfFirstMonth)
from (
select top (datediff(month,#DatFirstOfFirstMonth,#DatLast)+1)
n=row_number() over (order by (select 1))-1
from (values (1),(1),(1),(1),(1),(1),(1),(1)) a (n)
cross join (values (1),(1),(1),(1),(1),(1),(1),(1)) b (n)
cross join (values (1),(1),(1),(1),(1),(1),(1),(1)) c (n)
cross join (values (1),(1),(1),(1),(1),(1),(1),(1)) d (n)
) x

SSIS (SQL Server 2005) Does not trap SQL exception

I run an "Execute SQL Task" in SSIS
It runs a stored procedure which does some validation
In the Stored Procedure I have a RAISERROR command when something goes wrong.
However when I test for this, this task fails to abort.
I have Googled about this and found lots of references, but no solution that works for me.
I have upgraded my SQL Server 2005 to service pack 3, but this does not make any difference.
One reference suggests putting in PRINT statements when an exception is thrown, This does not work.
So how do I fix this?
The code in the stored procedure is;
ALTER PROCEDURE [dbo].[usp_VAL_Journey]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #Month AS INT
, #Year AS INT
SELECT TOP 1 #Year = DATEPART(YEAR, Date), #Month = DATEPART(MONTH, Date)
FROM dbo.JourneyLandingTable
SELECT TOP 1 *
FROM dbo.JourneyMasterTable
WHERE DATEPART(YEAR, Date) = #Year
AND DATEPART(MONTH, Date) = #Month
IF ##ROWCOUNT > 0
BEGIN
RAISERROR('JourneyMasterTable already contains data for this month.', 16, 1)
RETURN
END
SELECT DATEPART(YEAR, Date) AS year1, DATEPART(MONTH, Date) AS month1
FROM dbo.JourneyLandingTable
GROUP BY DATEPART(YEAR, Date), DATEPART(MONTH, Date)
IF ##ROWCOUNT > 1
BEGIN
RAISERROR('JourneyLandingTable contains data for more than 1 month.', 16, 1)
END
END
I have a similar thing but works fine for me. Not sure why it doesnt. The setup I have is I dont raiseerror at various places. I keep incrementing the error count and finally raise it as follows. It works perfectly - it aborts execution and all that good stuff.
declare #errorString varchar(100)
IF #rc > 0
BEGIN
set #errorString = 'Error(s) occured when trying to run sp_blahblah error count ' + cast(#rc as varchar(10))
raiserror(#errorString , 16, 1)
END
you might want to try returning some value "RETURN n"
ALTER PROCEDURE [dbo].[usp_VAL_Journey]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #Month AS INT
, #Year AS INT
SELECT TOP 1 #Year = DATEPART(YEAR, Date), #Month = DATEPART(MONTH, Date)
FROM dbo.JourneyLandingTable
SELECT TOP 1 *
FROM dbo.JourneyMasterTable
WHERE DATEPART(YEAR, Date) = #Year
AND DATEPART(MONTH, Date) = #Month
IF ##ROWCOUNT > 0
BEGIN
RAISERROR('JourneyMasterTable already contains data for this month.', 16, 1)
RETURN 10 --<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
END
SELECT DATEPART(YEAR, Date) AS year1, DATEPART(MONTH, Date) AS month1
FROM dbo.JourneyLandingTable
GROUP BY DATEPART(YEAR, Date), DATEPART(MONTH, Date)
IF ##ROWCOUNT > 1
BEGIN
RAISERROR('JourneyLandingTable contains data for more than 1 month.', 16, 1)
RETURN 20 --<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
END
END
you should be able to tell if that code block was hit by checking the procedure's return value.