How to set Parameters in SQL Server SProc? - sql-server

I have the following SProc, which works fine for me, but I am trying to create two parameters, to pass in two variables, and I actually have 0 parameters.
ALTER PROCEDURE [dbo].[TimeSeries]
AS
BEGIN
Drop Table UNION_SUMMARY
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SELECT *
INTO UNION_SUMMARY
FROM
(
Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_TMP_MG_MORTGAGE_SCHED_HIST_SPLIT' AS TBL From TBL_TMP_MG_MORTGAGE_SCHED_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FMDDATA_HIST_SPLIT' AS TBL From TBL_FMDDATA_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FR2052A_CDARS_HIST_SPLIT' AS TBL From TBL_FR2052A_CDARS_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FR2052A_OperationalDepositTag_SPLIT' AS TBL From TBL_FR2052A_OperationalDepositTag_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FR2052A_FXDH_REVAL_HIST_SPLIT' AS TBL From TBL_FR2052A_FXDH_REVAL_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_MULTI_ACCOUNT_HIST_SPLIT' AS TBL From TBL_MULTI_ACCOUNT_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_MULTI_LD_BALANCE_HIST_SPLIT' AS TBL From TBL_MULTI_LD_BALANCE_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_MULTI_LD_HIST_SPLIT' AS TBL From TBL_MULTI_LD_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FR2052A_SCHD_HIST_SPLIT' AS TBL From TBL_FR2052A_SCHD_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_MULTI_MG_FUTURE_BALANCE_HIST_SPLIT' AS TBL From TBL_MULTI_MG_FUTURE_BALANCE_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_MULTI_MM_HIST_SPLIT' AS TBL From TBL_MULTI_MM_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FR2052A_TPOS_HIST_SPLIT' AS TBL From TBL_FR2052A_TPOS_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FR2052A_AGG_BOC_HIST' AS TBL From TBL_FR2052A_AGG_BOC_HIST Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FR2052A_NB_IU_HIST' AS TBL From TBL_FR2052A_NB_IU_HIST Where AsOfDate Between #StartDate AND #EndDate
) a
END
I would expect to see 2 parameters here, but I see 0.

You need it in the proc declaration...
ALTER PROCEDURE [dbo].[TimeSeries] (#StartDate DATETIME,#EndDate DATETIME)
as...

Because your SP has no parameters. In the context of your Procedure, #StartDate and #EndDate are variables.
To declare a parameter, you need to put them in your CREATE/ALTER clause. For example:
ALTER PROCEDURE [dbo].[TimeSeries] #StartDate datetime, #EndDate datetime AS
BEGIN
DROP TABLE dbo.UNION_SUMMARY;
SELECT *
INTO dbo.UNION_SUMMARY
...
END

The syntax is as follows:
ALTER PROCEDURE [dbo].[TimeSeries]
#StartDate DATETIME,
#EndDate DATETIME
AS
BEGIN
Drop Table UNION_SUMMARY
SELECT *
INTO UNION_SUMMARY
FROM
(
Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_TMP_MG_MORTGAGE_SCHED_HIST_SPLIT' AS TBL From TBL_TMP_MG_MORTGAGE_SCHED_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FMDDATA_HIST_SPLIT' AS TBL From TBL_FMDDATA_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FR2052A_CDARS_HIST_SPLIT' AS TBL From TBL_FR2052A_CDARS_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FR2052A_OperationalDepositTag_SPLIT' AS TBL From TBL_FR2052A_OperationalDepositTag_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FR2052A_FXDH_REVAL_HIST_SPLIT' AS TBL From TBL_FR2052A_FXDH_REVAL_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_MULTI_ACCOUNT_HIST_SPLIT' AS TBL From TBL_MULTI_ACCOUNT_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_MULTI_LD_BALANCE_HIST_SPLIT' AS TBL From TBL_MULTI_LD_BALANCE_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_MULTI_LD_HIST_SPLIT' AS TBL From TBL_MULTI_LD_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FR2052A_SCHD_HIST_SPLIT' AS TBL From TBL_FR2052A_SCHD_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_MULTI_MG_FUTURE_BALANCE_HIST_SPLIT' AS TBL From TBL_MULTI_MG_FUTURE_BALANCE_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_MULTI_MM_HIST_SPLIT' AS TBL From TBL_MULTI_MM_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FR2052A_TPOS_HIST_SPLIT' AS TBL From TBL_FR2052A_TPOS_HIST_SPLIT Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FR2052A_AGG_BOC_HIST' AS TBL From TBL_FR2052A_AGG_BOC_HIST Where AsOfDate Between #StartDate AND #EndDate
Union Select AsOfDate,Portfolio,PID,Reportable_Amount,'TBL_FR2052A_NB_IU_HIST' AS TBL From TBL_FR2052A_NB_IU_HIST Where AsOfDate Between #StartDate AND #EndDate
) a
END

Related

Using Recursive query in function

I have this query developed with the help of a guy here and I am not able to use this in function.
There is some sort of Syntax issue.
Here is the query
WITH CTE AS (
SELECT #STARTDATE AS STARTDATE
UNION ALL
SELECT DATEADD(D,1,STARTDATE)
FROM CTE
WHERE STARTDATE <#ENDDATE
),
WORKINGDAYS AS (
SELECT STARTDATE,
DATENAME(DW,STARTDATE)WEEKDAYS,
C1.CalanderDayName AS isweekend
FROM CTE c
LEFT JOIN HRM.tbl_Calendar C1 ON DATENAME(DW,STARTDATE) = C1.CalanderDayName
AND C1.IsOffDay = 1
)
SELECT COUNT(WEEKDAYS)as WORKINGDAYS
FROM WORKINGDAYS
WHERE isweekend IS NULL;
I want to create a function named fnGetWorkingDays
ALTER FUNCTION [dbo].[fnGetWorkingDays] (#StartDate datetime, #EndDate datetime)
RETURNS int
AS
BEGIN
DECLARE #dateFrom datetime
DECLARE #dateTo datetime
SET #dateFrom = #StartDate
SET #dateTo = #EndDate
DECLARE #WORKDAYS INT
SELECT #WORKDAYS =
;WITH CTE AS (
SELECT #STARTDATE AS STARTDATE
UNION ALL
select DATEADD(D,1,STARTDATE)
FROM CTE
WHERE STARTDATE <#ENDDATE
)
,WORKINGDAYS AS (
SELECT STARTDATE,DATENAME(DW,STARTDATE)WEEKDAYS, C1.CalanderDayName AS isweekend
FROM CTE c
LEFT JOIN HRM.tbl_Calendar C1 ON DATENAME(DW,STARTDATE)=C1.CalanderDayName AND C1.IsOffDay=1
)
SELECT COUNT(WEEKDAYS)as WORKINGDAYS FROM WORKINGDAYS WHERE isweekend is null
RETURN #WORKDAYS
END
Try With this Below function .let me know back for any errors
CREATE FUNCTION [dbo].[fnGetWorkingDays] (#StartDate datetime, #EndDate datetime)
RETURNS int
AS
BEGIN
DECLARE #WORKDAYS INT
;WITH CTE AS (
SELECT #STARTDATE AS STARTDATE
UNION ALL
SELECT DATEADD(D,1,STARTDATE)
FROM CTE
WHERE STARTDATE <#ENDDATE
),
WORKINGDAYS AS (
SELECT STARTDATE,
DATENAME(DW,STARTDATE)WEEKDAYS,
C1.CalanderDayName AS isweekend
FROM CTE c
LEFT JOIN HRM.tbl_Calendar C1 ON DATENAME(DW,STARTDATE) = C1.CalanderDayName
AND C1.IsOffDay = 1
)
SELECT #WORKDAYS=COUNT(WEEKDAYS) FROM WORKINGDAYS WHERE isweekend is null
RETURN #WORKDAYS
END
You are getting the Error because your Assignment operation for the Variable #WORKDAYS is Wrong. Change it Like This
ALTER FUNCTION [dbo].[fnGetWorkingDays]
(
#StartDate DATETIME,
#EndDate DATETIME
)
RETURNS INT
AS
BEGIN
DECLARE #dateFrom DATETIME;
DECLARE #dateTo DATETIME;
SET #dateFrom = #StartDate;
SET #dateTo = #EndDate;
DECLARE #WORKDAYS INT;
WITH CTE
AS
(
SELECT
#STARTDATE AS STARTDATE
UNION ALL
SELECT
DATEADD(D, 1, STARTDATE)
FROM CTE
WHERE STARTDATE < #ENDDATE
),WORKINGDAYS
AS
(
SELECT
DATENAME(DW, STARTDATE) WEEKDAYS,
C1.CalanderDayName AS isweekend
FROM CTE c
LEFT JOIN HRM.tbl_Calendar C1
ON DATENAME(DW, STARTDATE) = C1.CalanderDayName
AND C1.IsOffDay = 1
)
SELECT
#WORKDAYS = COUNT(WEEKDAYS)--Asign Variable Here
FROM WORKINGDAYS
WHERE isweekend IS NULL;
RETURN #WORKDAYS;
END;
You have written wrong syntax to set #WORKDAYS, try below syntax
CREATE FUNCTION [dbo].[fnGetWorkingDays] (#StartDate datetime, #EndDate datetime)
RETURNS int
AS
BEGIN
DECLARE #WORKDAYS INT
;WITH CTE AS (
SELECT #STARTDATE AS STARTDATE
UNION ALL
select DATEADD(D,1,STARTDATE)
FROM CTE
WHERE STARTDATE <#ENDDATE
)
,WORKINGDAYS AS (
SELECT STARTDATE,DATENAME(DW,STARTDATE)WEEKDAYS, C1.CalanderDayName AS isweekend
FROM CTE c
LEFT JOIN HRM.tbl_Calendar C1 ON DATENAME(DW,STARTDATE)=C1.CalanderDayName AND C1.IsOffDay=1
)
SELECT #WORKDAYS=COUNT(WEEKDAYS) FROM WORKINGDAYS WHERE isweekend is null
RETURN #WORKDAYS
END

How to get days from date to date in SQL Server?

In SQL Server, I want to get days from date to date. Example: from 2015/12/28 to 2016/01/02, the result as
2015/12/28
2015/12/29
2015/12/30
2015/12/31
2016/01/01
2016/01/02
DECLARE #STARTDATE DATETIME = '2015-12-28'
DECLARE #ENDDATE DATETIME = '2016-01-02'
SELECT BETWEEN #STARTDATE AND #ENDDATE AS DAYS
Use CTE
DECLARE #STARTDATE DATE = '2015-12-28'
DECLARE #ENDDATE DATE = '2016-01-02'
;WITH CTE AS
(
SELECT #STARTDATE As dt
UNION ALL
SELECT DATEADD(D,1,dt) AS dt
FROM CTE
WHERE dt < #ENDDATE
)
SELECT * FROM CTE
You could build a calendar table, which would probably come in handy down the road. Or you could use a loop.
DECLARE #ENDDATE DATETIME = '2016-01-02'
DECLARE #DAY DATETIME = '2015-12-28'
WHILE #Day <= #ENDDATE
BEGIN
SELECT #DAY
SET #DAY = DATEADD(DD,1,#DAY)
END
Or for all of the days in one result set:
DECLARE #ENDDATE DATETIME = '2016-01-02'
DECLARE #DAY DATETIME = '2015-12-28'
DECLARE #TABLE TABLE (DATE DATETIME)
WHILE #Day <= #ENDDATE
BEGIN
INSERT #TABLE
VALUES (#DAY)
SET #DAY = DATEADD(DD,1,#DAY)
END
SELECT *
FROM #TABLE
You can specify the dates in your WHERE clause. For example, WHERE date >=#STARTDATE AND date <=#ENDDATE. That should return the full date in your results.
using Numbers table
select dateadd(day,n,startdate)
from numbers
where dateadd(day,n,startdate)<=enddate
order by n

Working days on SQL Server using CTE in a function

I'm trying to write a function to return the number of working days between 2 dates. I have a table with all the bank holidays in which has two fields: BHID and BHDate.
I've written the following SELECT query to test out my theory and it works nicely:
DECLARE #StartDate AS Date, #EndDate AS Date
SET #StartDate = '2015-01-01'
SET #EndDate = '2015-07-01'
;WITH CTE AS (
SELECT #StartDate AS StartDate, #EndDate AS EndDate, #StartDate AS DateCalc
UNION ALL
SELECT #StartDate AS StartDate, #EndDate AS EndDate, DATEADD(dd, 1, DateCalc) AS DateCalc FROM CTE
WHERE DATEADD(dd, 1, DateCalc) <= EndDate)
SELECT COUNT(*) AS Days
FROM CTE
LEFT JOIN psd.dbo.LUBankHolidays BH
ON CTE.DateCalc = BH.BHDate
WHERE BHID IS NULL
AND LEFT(DATENAME(dw, DateCalc) ,1) <> 'S'
option (Maxrecursion 0);
But when I try and put it in a function I get some errors around the SET line, it could be me just not being quite as good on functions as the rest of my knowledge or I was wondering whether it was to do with the CTE not having been used ahead of the SET line? Here's my attempt:
CREATE FUNCTION [dbo].[WorkingDays]
(#StartDate AS Date, #EndDate AS Date
)
RETURNS INT
AS
BEGIN
DECLARE #Days AS INT
;WITH CTE AS (
SELECT #StartDate AS StartDate, #EndDate AS EndDate, #StartDate AS DateCalc
UNION ALL
SELECT #StartDate AS StartDate, #EndDate AS EndDate, DATEADD(dd, 1, DateCalc) AS DateCalc FROM CTE
WHERE DATEADD(dd, 1, DateCalc) <= EndDate)
SET #Days =
(SELECT COUNT(*) AS Days
FROM CTE
LEFT JOIN psd.dbo.LUBankHolidays BH
ON CTE.DateCalc = BH.BHDate
WHERE BHID IS NULL
AND LEFT(DATENAME(dw, DateCalc) ,1) <> 'S'
option (Maxrecursion 0);)
RETURN #Days
END
I even tried inserting the result of the INT into a temporary table and then dropping this after setting #Days before then returning #Days but this then results in an error regarding not being allowed to produce temporary tables as part of a function.
Any help would be great, I'm sure it's a small thing but just escaping me currently.
Because a CTE can only be used in a query, rather than using SET to set the variable, use SELECT instead:
SELECT #Days =
(SELECT COUNT(*) AS Days
FROM CTE …
From MSDN:
A CTE must be followed by a single SELECT, INSERT, UPDATE, or DELETE
statement that references some or all the CTE columns.
Worked it out with stuartd's help:
CREATE FUNCTION [dbo].[WorkingDays]
(#StartDate AS Date, #EndDate AS Date
)
RETURNS INT
AS
BEGIN
DECLARE #Days AS INT
;WITH CTE AS (
SELECT #StartDate AS StartDate, #EndDate AS EndDate, #StartDate AS DateCalc
UNION ALL
SELECT #StartDate AS StartDate, #EndDate AS EndDate, DATEADD(dd, 1, DateCalc) AS DateCalc FROM CTE
WHERE DATEADD(dd, 1, DateCalc) <= EndDate)
SELECT #Days =
(SELECT COUNT(*) AS Days
FROM CTE
LEFT JOIN psd.dbo.LUBankHolidays BH
ON CTE.DateCalc = BH.BHDate
WHERE BHID IS NULL
AND LEFT(DATENAME(dw, DateCalc) ,1) <> 'S')
option (Maxrecursion 0);
RETURN #Days
END
Thanks All
Use this function
CREATE FUNCTION [dbo].[WorkingDays]
(#Start_Date AS Date, #end_Date AS Date
)
RETURNS INT
AS
BEGIN
DECLARE #Days AS INT
WITH AllDays
AS ( SELECT #start_date AS [Date], 1 AS [level]
UNION ALL
SELECT DATEADD(DAY, 1, [Date]), [level] + 1
FROM AllDays
WHERE [Date] < #end_date )
SELECT #Days =COUNT(*) AS Days
FROM AllDays
LEFT JOIN psd.dbo.LUBankHolidays BH
ON AllDays.Date= BH.BHDate
WHERE BHID IS NULL
AND LEFT(DATENAME(dw, AllDays.Date) ,1) <> 'S'
RETURN #Days
END

while taking count of two column result is not showing proper

I have a stored procedure like this:
ALTER procedure [dbo].[Driverperformance]
#Ecode nvarchar(50),
#startdate datetime,
#enddate datetime
as
begin
declare #date1 datetime = CONVERT(datetime, #startdate + ' 00:01:00.000', 120);
declare #date2 datetime = CONVERT(datetime, #enddate + ' 23:23:59.000', 120);
SELECT
e.Ecode,CAST(q.dtime AS DATE) as Date,
e.Ename,
count(q.Ecode) CntEcode ,
count(DelEcode) CntDelEcode
FROM EmployeeMaster_tbl e
inner JOIN Transaction_tbl q
ON e.Ecode = q.Ecode where q.Ecode=#Ecode
and dtime between '' + #date1 +'' and ''+#date2+''
group by
e.Ecode,
e.Ename,
CAST(q.dtime AS date)
ORDER BY CAST(q.dtime AS date)--e.Ecode DESC
end
but i am not getting Count of DelEcode proper ,what is wrong with my stored procedure
while i am checking count of DelEcode like this:select * from Transaction_tbl where dtime >='2013-09-03 00:00:00.000' and dtime <='2013-09-03 23:59:59.000' and DelEcode='E003' am getting 35 rows,but while executing the store procedure am getting only 23 counts of CntDelEcode
If you want to count the number of different "DelEcode" try count(distinct DelEcode). If not, you are going to count the number of records with not null DelEcode values. If you perform a join the count will be the result of the cartesian product, not the number of different DelEcodes.
I assume you use SQL Server 2008 or later as you have a CAST(... as date) in your code
There are several issues with your stored procedure:
A weird way to strip time (just cast to date)
A BETWEEN statement that compares strings instead of dates, because of the +'' statements.
Using datetime parameters when you actually need just date
The simplest way would be to rewrite the stored procedure like this
ALTER procedure [dbo].[Driverperformance]
#Ecode nvarchar(50),
#startdate date,
#enddate date
as
begin
SELECT
e.Ecode,CAST(q.dtime AS DATE) as Date,
e.Ename,
count(q.Ecode) AS CntEcode ,
count(DelEcode) AS CntDelEcode
FROM EmployeeMaster_tbl e
inner JOIN Transaction_tbl q
ON e.Ecode = q.Ecode
where q.Ecode=#Ecode
and #startdate <= dtime
and dtime < #enddate
group by
e.Ecode,
e.Ename,
CAST(q.dtime AS date)
ORDER BY CAST(q.dtime AS date)--e.Ecode DESC
end
You shouldn't have problems with code that calls this stored procedure and passes datetime values because the time portions will be truncated. You will encounter problems only if you pass string literals instead of dates, in formats that SQL Server can't identify from your settings
If you have to use datetime parameters in some other part of your stored procedure, you can do a simple cast to date:
ALTER procedure [dbo].[Driverperformance]
#Ecode nvarchar(50),
#startdate datetime,
#enddate datetime
as
begin
declare #date1 date= cast(#startdate as date);
declare #date2 date= cast(#enddate as date);
SELECT
e.Ecode,CAST(q.dtime AS DATE) as Date,
e.Ename,
count(q.Ecode) AS CntEcode ,
count(DelEcode) AS CntDelEcode
FROM EmployeeMaster_tbl e
inner JOIN Transaction_tbl q
ON e.Ecode = q.Ecode
where q.Ecode=#Ecode
and #date1 <= dtime
and dtime < #date2
group by
e.Ecode,
e.Ename,
CAST(q.dtime AS date)
ORDER BY CAST(q.dtime AS date)--e.Ecode DESC
end
You can also get rid of the ORDER BY statement by reordering your GROUP BY. Grouping orders the results, so you can use GROUP BY CAST(q.dtime AS date) , e.Ecode, e.Ename to get your results order by date, Ecode and Ename

Adding a further group into a recursive CTE

Referring back to this SO post
If there is a Grouping category "Category" which, for simplicity's sake, can be either X or Y - is it a trivial matter amending this script so that it will add in the missing dates for each of the categories ?
I assume the category will need adding into the CTE?
In other words if I have the following initial table:
...how do I get to the following:
Will upload my attempt shortly
I've called the initial table #x. I'm hoping to adapt a recursive CTE query like the following to include the field Category:
DECLARE #MinDate DATETIME;
SET #MinDate = (SELECT Min(DATE) FROM #x)
DECLARE #MaxDate DATETIME;
SET #MaxDate = (SELECT Max(DATE) FROM #x)
;WITH times AS
(
SELECT #MinDate dt , 1 depth
UNION ALL
SELECT
DATEADD(d, depth, #MinDate) dt
, 1 + depth as depth
FROM times
WHERE DATEADD(d, depth, #MinDate) <= #MaxDate
)
SELECT
*
FROM
TIMES t
LEFT OUTER JOIN #X x
ON
t.dt = x.Date
Ok - I've tied including a CROSS JOIN but it expands things incorrectly:
SELECT DISTINCT Category INTO #Cat FROM #x
DECLARE #MinDate DATETIME;
SET #MinDate = (SELECT Min(DATE) FROM #x)
DECLARE #MaxDate DATETIME;
SET #MaxDate = (SELECT Max(DATE) FROM #x)
;WITH times AS
(
SELECT
Category
, #MinDate dt
, 1 depth
FROM #Cat
UNION ALL
SELECT
c.Category
, DATEADD(d, depth, #MinDate) dt
, 1 + depth as depth
FROM
times t
CROSS JOIN #Cat c
--ON c.Category IS NOT NULL
WHERE DATEADD(d, depth, #MinDate) <= #MaxDate
)
SELECT
*
FROM
TIMES
This seems to have worked ok:
SELECT DISTINCT Category INTO #Cat FROM #x
DECLARE #MinDate DATETIME;
SET #MinDate = (SELECT Min(DATE) FROM #x)
DECLARE #MaxDate DATETIME;
SET #MaxDate = (SELECT Max(DATE) FROM #x)
;WITH times AS
(
SELECT
Category
, #MinDate dt
, 1 depth
FROM #Cat
UNION ALL
SELECT
Category
, DATEADD(d, depth, #MinDate) dt
, 1 + depth as depth
FROM
times t
WHERE DATEADD(d, depth, #MinDate) <= #MaxDate
)
SELECT
*
FROM
TIMES
Here is a solution without a calendar table (which is a must in production). You might have date range in variables, or you might go for min() and max() from the_table.
EDIT: shorter version incorporating categories into date range generation
declare #startdate datetime = '2012-1-1'
declare #enddate datetime = '2012-1-5'
; with dates([date], category) as (
select distinct #startdate, category
from the_table
union all
select dateadd (day, 1, [date]), category
from dates
where [date] < #enddate
)
select dates.date,
dates.category,
isnull(the_table.amount, 0) Amount
from dates
left join the_table
on dates.date = the_table.date
and dates.category = the_table.category
order by dates.category, dates.date
option (maxrecursion 0)
There is live test # Sql Fiddle.
New Sql Fiddle.
Something like this should do the trick:
declare #curDate datetime, #maxDate datetime
declare #count tinyint
select #curDate = convert(datetime, '20120101', 112), #maxDate = getdate()
select #count = 0
while #curDate < #maxDate
begin
select #count = count(1) from tablename where Category = 'X' and convert(varchar(8), Date, 112) = convert(varchar(8), #curDate, 112)
if #count > 0
begin
insert into tablename
select 'X', #curDate, 0
end
select #curDate = dateadd(dd, 1, #curDate)
end

Resources