Return 0 with dates having empty results [duplicate] - sql

I want to show all dates between two dates when there is any date data missing then its should show zero in val column .
declare #temp table (
id int identity(1,1) not null,
CDate smalldatetime ,
val int
)
INSERT STATEMENT FOR DATA TO CHECK
insert into #temp select '10/2/2012',1
insert into #temp select '10/3/2012',1
insert into #temp select '10/5/2012',1
insert into #temp select '10/7/2012',2
insert into #temp select '10/9/2012',2
insert into #temp select '10/10/2012',2
insert into #temp select '10/13/2012',2
insert into #temp select '10/15/2012',2
Retrieve records between first day of month and today
select * from #temp where CDate between '10/01/2012' AND '10/15/2012'
As i run this query its show me all data between these two dates but i want to also include missing dates with val=0
SQL FIDDLE WITH SAMPLE DATA

;with d(date) as (
select cast('10/01/2012' as datetime)
union all
select date+1
from d
where date < '10/15/2012'
)
select t.ID, d.date CDate, isnull(t.val, 0) val
from d
left join temp t
on t.CDate = d.date
order by d.date
OPTION (MAXRECURSION 0) -- use this if your dates are >99 days apart
You need to make up the dates, so I've use a recursive common table expression here.
SQL Fiddle
MAXRECURSION number
Specifies the maximum number of recursions allowed for this query. number is a nonnegative
integer between 0 and 32767. When 0 is specified, no limit is applied. If this option is
not specified, the default limit for the server is 100.
When the specified or default number for MAXRECURSION limit is reached during query
execution, the query is ended and an error is returned.

This will work as long as there are less than 2047 days between from and to dates
declare #from smalldatetime = '10/01/2012'
declare #to smalldatetime = '10/15/2012'
select t.id, dateadd(day, number,#from), isnull(val, 0) val from #temp t
right join master..spt_values s
on dateadd(d, s.number, #from) = t.CDate
where
datediff(day, #from, #to ) > s.number
and s.type = 'P'

I think the best way to do this is to create your own table with dates (you can also use master.dbo.spt_values, but I personally don't like that solution)
declare #Temp_Dates table (CDate datetime)
declare #Date datetime
select #Date = (select min(CDate) from temp)
while #Date <= (select max(CDate) from temp)
begin
insert into #Temp_Dates (CDate)
select #Date
select #Date = dateadd(dd, 1, #Date)
end
select D.CDate, isnull(T.id, 0) as id
from #Temp_Dates as D
left outer join temp as T on T.CDate = D.CDate
you can also use recursive solution with CTE

DECLARE #min DATETIME,
#max DATETIME,
#val INT
SELECT #min = Min(CDATE),
#max = Max(CDATE)
FROM TEMP
DECLARE #temp TABLE
(
CDATE SMALLDATETIME,
VAL INT
)
WHILE #min < #max
BEGIN
SELECT #val = VAL
FROM TEMP
WHERE CDATE = #min
INSERT #temp
VALUES (#min,
#val)
SET #min = Dateadd(D, 1, #min)
SET #val = 0
END
SELECT *
FROM #temp

Declare #temp Table(id int identity(1,1) not null,CDate smalldatetime ,val int)
insert into #temp select '10/2/2012',1
insert into #temp select '10/3/2012',1
insert into #temp select '10/5/2012',1
insert into #temp select '10/7/2012',2
insert into #temp select '10/9/2012',2
insert into #temp select '10/10/2012',2
insert into #temp select '10/13/2012',2
insert into #temp select '10/15/2012',2
DECLARE #startDate DATE= '10/01/2012'
DECLARE #endDate DATE= '10/15/2012'
SELECT t.Id, X.[Date],Val = COALESCE(t.val,0)
FROM
(SELECT [Date] = DATEADD(Day,Number,#startDate)
FROM master..spt_values
WHERE Type='P'
AND DATEADD(day,Number,#startDate) <= #endDate)X
LEFT JOIN #temp t
ON X.[Date] = t.CDate

using a recursive cte with min and max
declare #T table (id int identity(1,1) primary key, dt date not null, val int not null);
insert into #T (dt, val) values
('10/2/2012',1)
, ('10/3/2012',1)
, ('10/5/2012',1)
, ('10/7/2012',2)
, ('10/9/2012',2)
, ('10/10/2012',2)
, ('10/13/2012',2)
, ('10/15/2012',2);
--select * from #T;
with cte as
( select min(dt) as dt, max(dt) as mx
from #T
union all
select dateadd(dd, 1, dt), mx
from CTE
where dt < mx
)
select c.dt, isnull(t.val, 0) as val
from cte c
left join #T t
on c.dt = t.dt
order by c.dt
option (maxrecursion 0);
dt val
---------- -----------
2012-10-02 1
2012-10-03 1
2012-10-04 0
2012-10-05 1
2012-10-06 0
2012-10-07 2
2012-10-08 0
2012-10-09 2
2012-10-10 2
2012-10-11 0
2012-10-12 0
2012-10-13 2
2012-10-14 0
2012-10-15 2

Related

How to generate all dates for a date range extracted from two date columns in SQL

I have a table TEMP1 as :
Parameter Val From To
a 1 8/1/2018 8/5/2018
b 2 8/4/2018 8/8/2018
c 3 8/8/2018 8/13/2018
and i need the output like below:
Parameter Date Val
a 8/1/2018 1
a 8/2/2018 1
a 8/3/2018 1
a 8/4/2018 1
a 8/5/2018 1
b 8/4/2018 2
b 8/5/2018 2
b 8/6/2018 2
b 8/7/2018 2
b 8/8/2018 2
c 8/8/2018 3
c 8/9/2018 3
c 8/10/2018 3
c 8/11/2018 3
c 8/12/2018 3
c 8/13/2018 3
using SQL.
Use the select below to get the dates, join in your TEMP1 table to get the values you want.
CREATE TABLE #tmpDates( StartDate DATETIME, EndDate DATETIME )
INSERT INTO #tmpDates (StartDate, EndDate)VALUES( '2018-08-10', '2018-08-15')
GO
WITH myDates AS
(SELECT StartDate as aDate FROM #tmpDates AS td
UNION ALL
SELECT DATEADD(day, 1, aDate) AS aDate FROM myDates
INNER JOIN #tmpDates AS td ON myDates.aDate >= td.StartDate
WHERE DATEADD(day, 1, aDate) <= td.EndDate)
SELECT aDate, 1 as aValue
FROM myDates
INNER JOIN (SELECT StartDate, EndDate FROM #tmpDates AS td ) AS i ON 1=1
OPTION (MAXRECURSION 0);
DROP TABLE #tmpDates
DECLARE #StartDate DATE
DECLARE #EindDate DATE
SET #StartDate = '1990-01-01' -- << user input >> --
SET #EindDate = '2018-12-31' -- << user input >> --
IF OBJECT_ID ('TEMPDB..#Date') IS NOT NULL DROP TABLE #Date
IF OBJECT_ID ('TEMPDB..#Date') IS NULL CREATE TABLE #Date (Date_ DATE)
INSERT INTO #Date VALUES (#StartDate)
WHILE #StartDate < #EindDate
BEGIN
INSERT INTO #Date
SELECT DATEADD (DD, 1, #StartDate) AS Date
SET #StartDate = DATEADD (DD, 1, #StartDate)
END;
SELECT *
FROM #Date
CREATE TABLE #T (Parameter VARCHAR (10), VAL INT, [From] DATE, [To] Date)
INSERT INTO #T VALUES ('a', 1, '20180801', '20180805')
INSERT INTO #T VALUES ('b', 2, '20180804', '20180808')
INSERT INTO #T VALUES ('c', 3, '20180808', '20180813')
SELECT D.Date_, T.Parameter, T.VAL
FROM #Date AS D
INNER JOIN #T AS T ON D.Date_ >= T.[From] AND D.Date_ <= T.[To]
MySQL (prior to V8) does not have support for recursive queries. What you want to do is to join your table to a numbers table. You can create one on the fly if it not too big:
select t.parameter, (t.from + interval n - 1 day) day as date,
t.val
from temp1 t join
(select 1 as n union all
select 2 as n union all
select 3 as n union all
select 4 as n union all
select 5 as n
) n
on t.from + interval n - 1 day <= t.to;
I should note that you can also do this using a Calendar table.
You can make a cartesian join:
http://sqlfiddle.com/#!18/03a13/6
SELECT s.*
FROM temp1 s, (
select 1 'temp'
union all
select 2
union all
select 3
union all
select 4
union all
select 5
) ss
Try below query:
WITH cte AS
(SELECT Parameter,Val,From as dateval
UNION ALL
SELECT Parameter,Val,DATEADD(day, 1, dateval)
FROM cte WHERE DATEADD(day, 1, dateval) <= To
)
SELECT Parameter,Val,dateval
FROM cte
OPTION (MAXRECURSION 0);
You can use below SQL Query for to get your result.
This was using Cursor and column names and alias may need to change as per your requirements.
SET NOCOUNT ON
DECLARE #mindate date
DECLARE #maxdate date
DECLARE #parameter char(5)
DECLARE #value smallint
Declare #temp table( fromdate date, Parameter char(5),val smallint)
DECLARE cur_date CURSOR
STATIC FOR
SELECT [from],[to], [parameter],[val] from temp1
OPEN cur_date
IF ##CURSOR_ROWS > 0
BEGIN
FETCH NEXT FROM cur_date INTO #mindate,#maxdate,#parameter, #value
WHILE ##Fetch_status = 0
BEGIN
INSERT INTO #temp
SELECT TOP (DATEDIFF(DAY, #mindate, #maxdate) + 1)
Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #mindate), #parameter as Parameter, #value as Val
FROM sys.all_objects a
CROSS JOIN sys.all_objects b
FETCH NEXT FROM cur_date INTO #mindate,#maxdate,#parameter, #value
END
END
CLOSE cur_date
DEALLOCATE cur_date
SELECT * FROM #temp

Based on day fetch all dates - sql

I have start date, end date and name of days. How can fetch all dates between those two dates of that specific days in sql?
example data:
start_date:4/11/2018
end_date: 5/11/2018
days: monday, thursday
expected output: all dates between start and end date which comes on monday and thursday and store them in table
updated
my present code(not working)
; WITH CTE(dt)
AS
(
SELECT #P_FROM_DATE
UNION ALL
SELECT DATEADD(dw, 1, dt) FROM CTE
WHERE dt < #P_TO_DATE
)
INSERT INTO Table_name
(
ID
,DATE_TIME
,STATUS
,CREATED_DATE
,CREATED_BY
)
SELECT #P_ID
,(SELECT dt FROM CTE WHERE DATENAME(dw, dt) In ('tuesday','friday',null))
,'NOT SENT'
,CAST(GETDATE() AS DATE)
,#USER_ID
Another approach for generating dates between ranges can be like following query. This will be faster compared to CTE or WHILE loop.
DECLARE #StartDate DATETIME = '2018-04-11'
DECLARE #EndDate DATETIME = '2018-05-15'
SELECT #StartDate + RN AS DATE FROM
(
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)))-1 RN
FROM master..[spt_values] T1
) T
WHERE RN <= DATEDIFF(DAY,#StartDate,#EndDate)
AND DATENAME(dw,#StartDate + RN) IN('Monday','Thursday')
Note:
If the row count present in master..[spt_values] is not sufficient for the provided range, you can make a cross join with the same to get a bigger range like following.
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)))-1 RN
FROM master..[spt_values] T1
CROSS JOIN master..[spt_values] T2
By this you will be able to generate date between a range with gap of 6436369 days.
You can use a recursive common table expression (CTE) to generate a list of days. With datepart(dw, ...) you can filter for specific days of the week.
An example that creates a list of Mondays and Thursdays between March 1st and today:
create table ListOfDates (dt date);
with cte as
(
select cast('2018-03-01' as date) as dt -- First day of interval
union all
select dateadd(day, 1, dt)
from cte
where dt < getdate() -- Last day of interval
)
insert into ListOfDates
(dt)
select dt
from cte
where datepart(dw, dt) in (2, 5) -- 2=Monday and 5=Thursday
option (maxrecursion 0)
See it working at SQL Fiddle.
This will work for you:
DECLARE #table TABLE(
ID INT IDENTITY(1,1),
Date DATETIME,
Day VARCHAR(50)
)
DECLARE #Days TABLE(
ID INT IDENTITY(1,1),
Day VARCHAR(50)
)
INSERT INTO #Days VALUES ('Monday')
INSERT INTO #Days VALUES ('Thursday')
DECLARE #StartDate DATETIME='2018-01-01';
DECLARE #EndDate DATETIME=GETDATE();
DECLARE #Day VARCHAR(50)='Friday';
DECLARE #TempDate DATETIME=#StartDate;
WHILE CAST(#TempDate AS DATE)<=CAST(#EndDate AS DATE)
BEGIN
IF EXISTS (SELECT 1 FROM #Days WHERE DAY IN (DATENAME(dw,#TempDate)))
BEGIN
INSERT INTO #table
VALUES (
#TempDate, -- Date - datetime
DATENAME(dw,#TempDate) -- Day - varchar(50)
)
END
SET #TempDate=DATEADD(DAY,1,#TempDate)
END
SELECT * FROM #table
INSERT INTO TargetTab(dateCOL)
SELECT dateCOL
FROM tab
WHERE dateCOL >= startdate AND dateCOL <= enddate
AND (DATENAME(dw,dateCOL) ='Thursday' OR DATENAME(dw,dateCOL) = 'Monday')
Try this query to get your result.
Use a recursive CTE to generate your dates, then filter by week day.
SET DATEFIRST 1 -- 1: Monday, 7 Sunday
DECLARE #StartDate DATE = '2018-04-11'
DECLARE #EndDate DATE = '2018-05-15'
DECLARE #WeekDays TABLE (WeekDayNumber INT)
INSERT INTO #WeekDays (
WeekDayNumber)
VALUES
(1), -- Monday
(4) -- Thursday
;WITH GeneratingDates AS
(
SELECT
GeneratedDate = #StartDate,
WeekDay = DATEPART(WEEKDAY, #StartDate)
UNION ALL
SELECT
GeneratedDate = DATEADD(DAY, 1, G.GeneratedDate),
WeekDay = DATEPART(WEEKDAY, DATEADD(DAY, 1, G.GeneratedDate))
FROM
GeneratingDates AS G -- Notice that we are referencing a CTE that we are also declaring
WHERE
G.GeneratedDate < #EndDate
)
SELECT
G.GeneratedDate
FROM
GeneratingDates AS G
INNER JOIN #WeekDays AS W ON G.WeekDay = W.WeekDayNumber
OPTION
(MAXRECURSION 30000)
Try this:
declare #start date = '04-11-2018'
declare #end date = '05-11-2018'
declare #P_ID int = 1
declare #USER_ID int = 11
;with cte as(
select #start [date]
union all
select dateadd(DAY, 1, [date]) from cte
where [date] < #end
)
--if MY_TABLE doesn't exist
select #P_ID,
[date],
'NOT SENT',
cast(getdate() as date),
#USER_ID
into MY_TABLE
from cte
--here you can specify days: 1 - Sunday, 2 - Monday, etc.
where DATEPART(dw,[date]) in (2, 5)
option (maxrecursion 0)
--if MY_TABLE does exist
--insert into MY_TABLE
--select #P_ID,
-- [date],
-- 'NOT SENT',
-- cast(getdate() as date),
-- #USER_ID
--from cte
--where DATEPART(dw,[date]) in (2, 5)
--option (maxrecursion 0)

Convert Procedural Approach into Set Based Approach in Sql-Server

We are using procedural approach (while loop) for inserting records into a particular table. the insert syntax is like below,
DECLARE #CNT INT = 0,
#WEEK DATE = '2015-11-01',
#FLAG INT
CREATE TABLE #Tmpdata (officeId int,id smallint, weekDate date,startsOn varchar(10),endsOn varchar(10),flag bit);
WHILE (#CNT <7)
BEGIN
SET #WEEK = DATEADD(D,#CNT,#WEEK )
IF EXISTS
(SELECT 1
FROM YEARRANGE
WHERE #WEEK BETWEEN CONVERT(DATE,taxseasonbegin)
AND CONVERT (DATE,taxSeasonEnd)
)
BEGIN
SET #FLAG =1
END
ELSE
BEGIN
SET #FLAG = 0
END
INSERT INTO #Tmpdata
(
officeId,id,weekDate,startsOn,endsOn,flag
)
VALUES
(
5134,#lvCounter,#week,'09:00 AM','05:00 PM',#flag
);
SET #cnt=#cnt+1;
end
(NOTE : TaxSeason is from january to august).
Is it possible to re-write the above logic in set based approach?
This is making a number of assumption because you didn't post ddl or any consumable sample data. Also, there is a variable #lvCounter not defined in your code. This is perfect opportunity to use a tally or numbers table instead of a loop.
declare #lvCounter int = 42;
DECLARE #CNT INT = 0,
#WEEK DATE = '2015-11-01',
#FLAG INT;
WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n))
, cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E1
)
select 5134 as officeId
, #lvCounter as Id
, DATEADD(DAY, N - 1, #WEEK) as weekDate
, '09:00 AM' as startsOn
, '05:00 PM' as EndOn
, Flag
from cteTally t
cross apply
(
select CAST(count(*) as bit) as Flag
from YearRange
where DATEADD(Day, t.N, #WEEK) > CONVERT(DATE,taxseasonbegin)
AND DATEADD(Day, t.N, #WEEK) <= CONVERT (DATE,taxSeasonEnd)
) y
where t.N <= 7;
Please can you provide sample data?
You can do something like:
SELECT DateIncrement = SUM(DATEADD(D,#CNT,#WEEK)) OVER (ORDER BY officeID)
FROM...
This gets an incremented date value for each record which you can then check against your start and end dates.
You could try some Kind of this one. This gives you the data I think you Need for your insert. I do not have a table named YEARRANGE so I couldn't test it completely
DECLARE #CNT INT = 0, #WEEK DATE = '2015-11-01', #FLAG INT;
CREATE TABLE #Tmpdata (officeId int,id smallint, weekDate date,startsOn varchar(10),endsOn varchar(10),flag bit);
WITH CTE AS
(
SELECT num AS cnt,
DATEADD(D, SUM(num) OVER(ORDER BY num ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
, #WEEK) AS [week]
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY nl) -1 AS num
FROM
(SELECT NULL AS nl UNION ALL SELECT NULL AS nl UNION ALL SELECT NULL AS nl UNION ALL SELECT NULL AS nl
UNION ALL SELECT NULL AS nl UNION ALL SELECT NULL AS nl UNION ALL SELECT NULL AS nl
) AS ni
) AS no
)
INSERT INTO #Tmpdata (officeId,id,weekDate,startsOn,endsOn,flag)
SELECT 5134 AS officeID, cnt AS id, [week],'09:00 AM' AS startsOn,'05:00 PM' AS endsOn, COALESCE(A1.flag,0) AS flag
FROM CTE
OUTER APPLY (SELECT 1
FROM YEARRANGE
WHERE [week] BETWEEN CONVERT(DATE,taxseasonbegin)
AND CONVERT (DATE,taxSeasonEnd)
) AS A1(flag);

Populating a Datetime Column

I want to populate a datetime column on the fly within a stored procedure. below is the query that I currently have that does same but slows down query performance.
CREATE TABLE #TaxVal
(
ID INT
, PaidDate DATETIME
, CustID INT
, CompID INT
)
INSERT INTO #TaxVal(ID, PaidDate, CustID, CompID)
VALUES(01, '20150201',12, 100)
, (03,'20150301', 18,101)
, (10,'20150401',19,22)
, (17,'20150401',02,11)
, (11,'20150411',18,201)
, (78,'20150421',18,299)
, (133,'20150407',18,101)
-- SELECT * FROM #TaxVal
DECLARE #StartDate DATETIME = '20150101'
, #EndDate DATETIME = '20150501'
DECLARE #Tab TABLE
(
CompID INT
, DateField DATETIME
)
DECLARE #T INT
SET #T = 0
WHILE #EndDate >= #StartDate + #T
BEGIN
INSERT INTO #Tab
SELECT CompID
, #StartDate + #T AS DateField
FROM #TaxVal
WHERE CustID = 18
AND CompID = 101
ORDER BY DateField DESC
SET #T = #T + 1
END
SELECT DISTINCT * FROM #Tab
DROP TABLE #TaxVal
Which is the best way to write this query for better performance?
Change this:
DECLARE #T INT
SET #T = 0
WHILE #EndDate >= #StartDate + #T
BEGIN
INSERT INTO #Tab
SELECT CompID
, #StartDate + #T AS DateField
FROM #TaxVal
WHERE CustID = 18
AND CompID = 101
ORDER BY DateField DESC
SET #T = #T + 1
END
to this:
;with cte as(
select cast('20150101' as date) as d
union all
select dateadd(dd, 1, d) as d from cte where d < '20150501'
)
INSERT INTO #Tab
SELECT CompID, d
FROM #TaxVal
cross join cte
WHERE CustID = 18 AND CompID = 101
Option(maxrecursion 0)
Here is recursive common table expression to get all dates in range. Then you do a cross join and insert. Notice that there is no sense to order set while inserting.
Giorgi's answer of
;with cte as(
select cast('20150101' as date) as d
union all
select dateadd(dd, 1, d) as d from cte where d < '20150501'
)
INSERT INTO #Tab
SELECT CompID, d
FROM #TaxVal
cross join cte
WHERE CustID = 18 AND CompID = 101
will work, but be careful with recursive CTE's. If the date range is large, you'll quickly hit your maximum recursion level. Often, a numbers table is used much like HABO mentioned. This is simply a table with a single column that only a integer so the rows would be 1, 2, 3, 4, 5, etc. You can then join the Numbers table (outer apply works well for this) and use the numbers with dateadd to get your incremental dates. Also note that you can run into an issue where the Numbers table doesn't contain enough rows for you date range.

SHOW ALL Dates data between two dates; if no row exists for particular date then show zero in all columns

I want to show all dates between two dates when there is any date data missing then its should show zero in val column .
declare #temp table (
id int identity(1,1) not null,
CDate smalldatetime ,
val int
)
INSERT STATEMENT FOR DATA TO CHECK
insert into #temp select '10/2/2012',1
insert into #temp select '10/3/2012',1
insert into #temp select '10/5/2012',1
insert into #temp select '10/7/2012',2
insert into #temp select '10/9/2012',2
insert into #temp select '10/10/2012',2
insert into #temp select '10/13/2012',2
insert into #temp select '10/15/2012',2
Retrieve records between first day of month and today
select * from #temp where CDate between '10/01/2012' AND '10/15/2012'
As i run this query its show me all data between these two dates but i want to also include missing dates with val=0
SQL FIDDLE WITH SAMPLE DATA
;with d(date) as (
select cast('10/01/2012' as datetime)
union all
select date+1
from d
where date < '10/15/2012'
)
select t.ID, d.date CDate, isnull(t.val, 0) val
from d
left join temp t
on t.CDate = d.date
order by d.date
OPTION (MAXRECURSION 0) -- use this if your dates are >99 days apart
You need to make up the dates, so I've use a recursive common table expression here.
SQL Fiddle
MAXRECURSION number
Specifies the maximum number of recursions allowed for this query. number is a nonnegative
integer between 0 and 32767. When 0 is specified, no limit is applied. If this option is
not specified, the default limit for the server is 100.
When the specified or default number for MAXRECURSION limit is reached during query
execution, the query is ended and an error is returned.
This will work as long as there are less than 2047 days between from and to dates
declare #from smalldatetime = '10/01/2012'
declare #to smalldatetime = '10/15/2012'
select t.id, dateadd(day, number,#from), isnull(val, 0) val from #temp t
right join master..spt_values s
on dateadd(d, s.number, #from) = t.CDate
where
datediff(day, #from, #to ) > s.number
and s.type = 'P'
I think the best way to do this is to create your own table with dates (you can also use master.dbo.spt_values, but I personally don't like that solution)
declare #Temp_Dates table (CDate datetime)
declare #Date datetime
select #Date = (select min(CDate) from temp)
while #Date <= (select max(CDate) from temp)
begin
insert into #Temp_Dates (CDate)
select #Date
select #Date = dateadd(dd, 1, #Date)
end
select D.CDate, isnull(T.id, 0) as id
from #Temp_Dates as D
left outer join temp as T on T.CDate = D.CDate
you can also use recursive solution with CTE
DECLARE #min DATETIME,
#max DATETIME,
#val INT
SELECT #min = Min(CDATE),
#max = Max(CDATE)
FROM TEMP
DECLARE #temp TABLE
(
CDATE SMALLDATETIME,
VAL INT
)
WHILE #min < #max
BEGIN
SELECT #val = VAL
FROM TEMP
WHERE CDATE = #min
INSERT #temp
VALUES (#min,
#val)
SET #min = Dateadd(D, 1, #min)
SET #val = 0
END
SELECT *
FROM #temp
Declare #temp Table(id int identity(1,1) not null,CDate smalldatetime ,val int)
insert into #temp select '10/2/2012',1
insert into #temp select '10/3/2012',1
insert into #temp select '10/5/2012',1
insert into #temp select '10/7/2012',2
insert into #temp select '10/9/2012',2
insert into #temp select '10/10/2012',2
insert into #temp select '10/13/2012',2
insert into #temp select '10/15/2012',2
DECLARE #startDate DATE= '10/01/2012'
DECLARE #endDate DATE= '10/15/2012'
SELECT t.Id, X.[Date],Val = COALESCE(t.val,0)
FROM
(SELECT [Date] = DATEADD(Day,Number,#startDate)
FROM master..spt_values
WHERE Type='P'
AND DATEADD(day,Number,#startDate) <= #endDate)X
LEFT JOIN #temp t
ON X.[Date] = t.CDate
using a recursive cte with min and max
declare #T table (id int identity(1,1) primary key, dt date not null, val int not null);
insert into #T (dt, val) values
('10/2/2012',1)
, ('10/3/2012',1)
, ('10/5/2012',1)
, ('10/7/2012',2)
, ('10/9/2012',2)
, ('10/10/2012',2)
, ('10/13/2012',2)
, ('10/15/2012',2);
--select * from #T;
with cte as
( select min(dt) as dt, max(dt) as mx
from #T
union all
select dateadd(dd, 1, dt), mx
from CTE
where dt < mx
)
select c.dt, isnull(t.val, 0) as val
from cte c
left join #T t
on c.dt = t.dt
order by c.dt
option (maxrecursion 0);
dt val
---------- -----------
2012-10-02 1
2012-10-03 1
2012-10-04 0
2012-10-05 1
2012-10-06 0
2012-10-07 2
2012-10-08 0
2012-10-09 2
2012-10-10 2
2012-10-11 0
2012-10-12 0
2012-10-13 2
2012-10-14 0
2012-10-15 2