I want to recursively loop though the temporary table by date1 field using following query in Sql server. I want that the #stardate and #enddate should auto increment up to the #stopcriteria initially starting from
'01/01/2011' to 12/31/2011' and then
'01/01/2012' to 12/31/2012' and so on up to #stopCriteria and resultset should keep joining with union. I have written following query using cte but is not working.
CREATE TABLE #tempbbs576 ( id int, amount money, date1 date)
insert into #tempbbs576(id,amount,date1) values(1,1000,'1/1/2018')
insert into #tempbbs576(id,amount,date1) values(2,20010,'22/3/2019')
insert into #tempbbs576(id,amount,date1) values(3,40010,'1/1/2017')
insert into #tempbbs576(id,amount,date1) values(4,50010,'23/4/2018')
insert into #tempbbs576(id,amount,date1) values(5,60010,'1/1/2018')
insert into #tempbbs576(id,amount,date1) values(6,70010,'21/1/2018')
DECLARE #startDate DATE;
DECLARE #endDate DATE;
DECLARE #stopCriteria DATE;
SET #startDate='01/01/2011'; SET #endDate='12/31/2011'; SET #stopCriteria='01/01/2018';
;WITH ctesequence
AS (SELECT 'Year' + Datename(year, Dateadd(year, 1, #startDate)) /*'2012'*/
AS FiscalYear, Count(DISTINCT id) AS Last2Years
FROM [dbo].[#tempbbs576](nolock) WHERE date1 BETWEEN #startDate AND
#endDate AND id IN (SELECT id FROM [dbo].[#tempbbs576]
WHERE date1 < Dateadd(year, -1, #startDate) AND id
NOT IN (SELECT id FROM [dbo].[#tempbbs576] WHERE date1 BETWEEN
Dateadd(year,-1, #startDate) AND Dateadd( year, -1, #endDate ) ))
UNION
SELECT 'Year' + Datename(year, Dateadd(year, 1, #startDate)) /*'2012'*/
AS FiscalYear, Count(DISTINCT id) AS Last2Years FROM ctesequence WHERE date1 <= #stopCriteria)
SELECT * FROM ctesequence OPTION(maxrecursion 0)
Please let me know if it is possible through cte.
Thanks in Advance,
Amar
Related
I have an SQL Statement which accepts a parameter #EndDate as DateTime. I want to be able to pass several values for #EndDate one by one and then Union the results of all the Queries. I have tried using CTE for this but it is of no use. I want to pass several Dates for #EndDate. Any help would be greatly appreciated.
My Query is:
DECLARE #EndDate as DateTime
SET #EndDate = '2018/02/25'
SELECT
CONVERT(VARCHAR, #EndDate, 101) [R_Date]
,[Name]
[Type]
FROM [dbo].[S_Table]
This is Sample query how u can loop through multiple dates. A while loop should select all rows into one table, do not need to perform union all
DECLARE #table TABLE (
day INT
,Month INT
,DATE DATE
)
DECLARE #startdate DATE = '2018/02/25'
DECLARE #enddate DATE = cast(getdate() AS DATE)
WHILE #startdate <= #enddate
BEGIN
SELECT #startdate = dateadd(dd, 1, #startdate)
INSERT #table (
day
,Month
,DATE
)
SELECT day(#startdate)
,MONTH(#startdate)
,#startdate
END
SELECT *
FROM #table;
In your logic for passing multiple values into query , you can store result set into temporal table, which holds looped records
DECLARE #table TABLE (
[R_Date] DATE
,Name VARCHAR(155)
,Value VARCHAR(155)
)
DECLARE #enddate DATE = '2018/02/25'
DECLARE #enddate1 DATE = cast(getdate() AS DATE)
WHILE #enddate <= #enddate1
BEGIN
SELECT #enddate = dateadd(dd, 1, #enddate)
INSERT #table (
R_Date
,Name
,Value
)
SELECT CONVERT(VARCHAR, #EndDate, 101) [R_Date]
,[Name] [Type]
FROM [dbo].[S_Table]
WHERE DATE = #enddate
-------More filters
END
SELECT *
FROM #table;
I need to have a function to get all the week numbers in a given date range.
I have to seperate this from my stored procedure since it has a lengthy process.
But when I use #tables in side the function it gives following error
Msg 2772, Level 16, State 1, Procedure WeekNumbersWithinRange, Line 19
Cannot access temporary tables from within a function.
And here is my function.
CREATE FUNCTION WeekNumbersWithinRange
(
#FromDate DATETIME,
#ToDate DATETIME
)
RETURNS TABLE
AS
BEGIN
IF OBJECT_ID (N'tempdb..#WeeksofRange', N'U') IS NOT NULL
BEGIN
DROP TABLE #WeeksofRange
END
CREATE TABLE #WeeksofRange (WeekNo INT);
-- Get all week numbers for the given delivery date range
IF OBJECT_ID (N'tempdb..#Calendar', N'U') IS NOT NULL
BEGIN
DROP TABLE #Calendar
END
CREATE TABLE #Calendar
(
CalendarDate DATE PRIMARY KEY,
IsWeekend BIT,
YearNo SMALLINT,
QuarterNo TINYINT,
MonthNo TINYINT,
DayOfYearNo SMALLINT,
DayNo TINYINT,
WeekNo TINYINT,
WeekDayNo TINYINT
)
DECLARE #beginDate DATE, #endDate DATE
SELECT
#beginDate = #FromDate, #endDate = #ToDate
WHILE #beginDate <= #endDate
BEGIN
INSERT INTO #Calendar (CalendarDate, IsWeekend, YearNo, QuarterNo, MonthNo, DayOfYearNo, DayNo, WeekNo, WeekDayNo)
SELECT
#beginDate As CalendarDate,
(CASE WHEN DATEPART(Weekday, #beginDate) IN (7, 1)
THEN 1 ELSE 0
END) AS IsWeekend,
DATEPART(Year, #beginDate) AS YearNo,
DATEPART(QUARTER, #beginDate) AS QuarterNo,
DATEPART(MONTH, #beginDate) AS MonthNo,
DATEPART(DayOfYear, #beginDate) AS DayOfYearNo,
DATEPART(Day, #beginDate) AS DayNo,
DATEPART(Week, #beginDate) AS WeekNo,
DATEPART(WEEKDAY, #beginDate) AS WeekDayNo
--,(Case When #beginDate < '02/03/2011' Then 0 Else DATEPART(Week, #beginDate) - 5 End) As mySpecificWeekNo
SET #beginDate = DATEADD(Day, 1, #beginDate)
END
INSERT INTO #WeeksofRange
SELECT DISTINCT WeekNo
FROM #Calendar;
-- End of Select all week numbers in the range
SELECT * FROM #WeeksofRange
GO
Is there any other way to do this? Or do I need to write this logic inside my stored procedure?
You cannot use a Temp table in UDF because
the object can't be created inside UDF.
Instead of using a Temp table, use a table variable, that should solve your problem
CREATE FUNCTION WeekNumbersWithinRange
(
#FromDate DATETIME,
#ToDate DATETIME
)
RETURNS TABLE
AS
BEGIN
DECLARE #WeeksofRange TABLE
(
WeekNo INT
)
-- Get all week numbers for the given delivery date range
declare #Calendar table
(CalendarDate Date Primary key, IsWeekend Bit, YearNo SmallInt, QuarterNo TinyInt, MonthNo TinyInt, DayOfYearNo SmallInt, DayNo TinyInt, WeekNo TinyInt, WeekDayNo TinyInt )
Declare #beginDate Date, #endDate Date
Select #beginDate = #FromDate , #endDate = #ToDate
While #beginDate <= #endDate
Begin
Insert Into #Calendar (CalendarDate, IsWeekend, YearNo, QuarterNo, MonthNo, DayOfYearNo, DayNo, WeekNo, WeekDayNo)
Select
#beginDate As CalendarDate
,(Case When DATEPART(Weekday, #beginDate) In (7, 1) Then 1 Else 0 End) As IsWeekend
,DATEPART(Year, #beginDate) As YearNo
,DATEPART(QUARTER, #beginDate) As QuarterNo
,DATEPART(MONTH, #beginDate) As MonthNo
,DATEPART(DayOfYear, #beginDate) As DayOfYearNo
,DATEPART(Day, #beginDate) As DayNo
,DATEPART(Week, #beginDate) As WeekNo
,DATEPART(WEEKDAY, #beginDate) As WeekDayNo
--,(Case When #beginDate < '02/03/2011' Then 0 Else DATEPART(Week, #beginDate) - 5 End) As mySpecificWeekNo
Set #beginDate = DateAdd(Day, 1, #beginDate)
End
INSERT INTO #calendar
SELECT DISTINCT WeekNo FROM #Calendar;
-- End of Select all week numbers in the range
SELECT * FROM #WeeksofRange
GO
I'd normally choose to make the Calendar table permanent and populate it with, say, a centuries worth of rows. And then just query it.
But, if you have to have this function, you can write it to use a CTE and avoid any explicit state/iteration management:
CREATE FUNCTION WeekNumbersWithinRange
(
#FromDate DATETIME,
#ToDate DATETIME
)
RETURNS TABLE
AS
return (With Weeks as (
select DATEPART(week,#FromDate) as Week,#FromDate as dt
union all
select DATEPART(week,ndt),ndt
from Weeks
cross apply (select DATEADD(day,7,dt) as ndt) t
where
ndt < #ToDate
)
select Week from Weeks
union
select DATEPART(week,#ToDate)
)
I've made the simplifying assumption that week numbers only change every 7 days so we don't need to generate a row for every day inside the CTE. Also, I use the final UNION to make sure that the final week is included. It could be skipped since I'm working in 7 day increments, so we could jump our value straight from a previous week to a value greater than #ToDate.
Depending on the ranges you're working with, you may have to apply the MAXRECURSION option to the query to allow the CTE to work fully.
I have start date & Mdate as columns in table, i want to do something like below in SQL
Add 1 month to Start_Date until start date > Mdate
I tried using while and if concepts, but no luck.
DECLARE #MIGRATIONDATE DATE, #STRT_DATE DATE, #NEXTD DATE
SET #MIGRATIONDATE =20140725
SET #STRT_DATE = 20140521
SELECT WHILE ( #STRT_DATE > #MIGRATIONDATE)
BEGIN
DATEADD(MM,1,#STRT_DATE))
END
appreciate if you can guide me on this?
I do not know if you would like to get one row of that table. If you want to do it for each row, then you should wrap it in a function and use CROSS APPLY.
declare
#startdate datetime,
#enddate datetime
set #startdate = '20140101'
set #enddate = '20150101'
;WITH date_range (thedate) AS (
select #startdate
UNION ALL SELECT DATEADD(MONTH, 1, thedate)
FROM date_range
WHERE DATEADD(MONTH, 1, thedate) <= #enddate
)
SELECT thedate FROM date_range
If you wanted in a function:
CREATE FUNCTION [dbo].[ExplodeDates](#startdate datetime, #enddate datetime)
returns table as
return (
WITH date_range (thedate) AS (
select #startdate
UNION ALL SELECT DATEADD(DAY, 1, thedate)
FROM date_range
WHERE DATEADD(DAY, 1, thedate) <= #enddate
)
SELECT thedate FROM date_range
);
SELECT Id,thedate
FROM Table1 T1
CROSS APPLY [dbo].[ExplodeDates](T1.StartDate,T1.EndDate)
select
case when start_date<Mdate then dateadd(mm,1,start_date) else start_date end
from yourTable
suppose start_date is 20140721 and MigrationDate is 20140525 then it returns you with gives you accepted result
select case
when convert( date,'20140721') <convert(date,'20140525')
then dateadd(mm,1,'20140721') else '20140721' end
How about (SQL Fiddle):
SELECT DATEADD(month,
DATEDIFF(month, Start_Date, Mdate) + 1,
Start_Date) AS NEW_START_DATE
FROM MyTable;
If there is a possibility of the Start_Date being greater than or equal to Mdate then use the following (SQL Fiddle):
SELECT Start_Date AS OLD_START_DATE,
CASE WHEN DATEDIFF(month, Start_Date, Mdate) > 0
THEN DATEADD(month, DATEDIFF(month, Start_Date, Mdate) + 1, Start_Date)
ELSE Start_Date END AS NEW_START_DATE,
Mdate
FROM MyTable;
I wish to create a temp table with 1 datetime column and then fill it with date(30 days before today). I wish to do all these in a select-from statement.
I could do it with a "WITH" loop as below prior to the select-from statement. However, I wish to do it within a select-from statement.
declare #endDate datetime
set #endDate = dateadd(day,-30,getdate())
with CTE_Table (
Select dataDate = dateadd(day,-1,getdate()) from CTE_Table
where datediff(day,dataDate,#endDate) < 0
)
select * from CTE_Table
Please help... :....(
You can use SELECT ... INTO.
BTW Your recursive CTE is invalid. A fixed version is below
DECLARE #endDate DATETIME
SET #endDate = dateadd(day, -30, getdate());
WITH CTE_Table(dataDate)
AS (SELECT dateadd(day, -1, getdate())
UNION ALL
SELECT dateadd(day, -1, dataDate)
FROM CTE_Table
WHERE datediff(day, dataDate, #endDate) < 0)
SELECT dataDate
INTO #T
FROM CTE_Table
You could do:
CREATE TABLE #temptable
(
DateColumn DATETIME
)
INSERT INTO #temptable
SELECT dataDate FROM CTE_Table
I want to split date range in months. I will pass startdate(1-jan-2011) and enddate(31-dec-2011) as a parameter then it must return result like
1-jan-2011 - 31-jan-2011
1-feb-2011 - 28-feb-2011
1-mar-2011 - 31-mar-2011
Please send me a stored procedure.....
Thanks,
Abhishek
Try this:
CREATE PROC SplitDateRange
#from DATETIME,
#to DATETIME
AS
BEGIN
SET NOCOUNT ON;
SET #from = CONVERT(VARCHAR, DATEADD(DAY, -DATEPART(DAY, #from)+1, #from), 112)
-- Sql 2000
CREATE TABLE #temp (DateFrom DATETIME, DateTo DATETIME)
WHILE #from < #to
BEGIN
INSERT #temp VALUES (#from, DATEADD(DAY, -1, DATEADD(MONTH, 1, #from)))
SET #from = DATEADD(MONTH, 1, #from)
END
SELECT * FROM #temp
DROP TABLE #temp
--sql 2005+
/*
;WITH Ranges(DateFrom, DateTo) AS
(
SELECT #from DateFrom, DATEADD(DAY, -1, DATEADD(MONTH, 1, #from)) DateTo
UNION ALL
SELECT DATEADD(MONTH, 1, DateFrom), DATEADD(DAY, -1, DATEADD(MONTH, 1, DATEADD(MONTH, 1, DateFrom)))
FROM Ranges
WHERE DateFrom < DATEADD(MONTH, -1, #To)
)
SELECT * FROM Ranges
OPTION(MAXRECURSION 0)
*/
END
GO
EXEC SplitDateRange '2011-01-02', '2012-06-06'
So that you can use the results in another SQL Query (which I assume is where you're going) I'd put that into a table valued function.
Assuming SQL Server 2005+ you could use this...
CREATE FUNCTION dbo.ufnMonthlyIntervals(
#from_date SMALLDATETIME,
#end_date SMALLDATETIME
)
RETURNS TABLE
WITH
intervals (
from_date,
end_date
)
AS
(
SELECT #from_date, DATEADD(MONTH, 1, #from_date ) - 1
UNION ALL
SELECT end_date + 1, DATEADD(MONTH, 1, end_date + 1) - 1 FROM intervals WHERE end_date < #end_date
)
RETURN
SELECT
from_date,
CASE WHEN end_date > #end_date THEN #end_date ELSE end_date END AS end_date
FROM
intervals
Then you just use SELECT * FROM dbo.ufnMonthlyIntervals('20110101', '20111201') AS intervals