This question has already been posted before, however, the correct answer doesn't seem to work, so I'm asking it again.
This code, should return the last 31 days with zero if there are no records;
SELECT dates.Date as Dates, isnull(Sum(ElapsedTimeSeconds),0) as ElapsedSeconds
FROM
[fnDateTable] (dateadd("m",-1,CONVERT(VARCHAR(10),GETDATE(),111)),CONVERT(VARCHAR(10),GETDATE(),111),'day') dates
LEFT JOIN UsersApplog on dates.date = UsersAppLog.LoggedDate
group by Dates.Date
See the [fnDateTable] here; fnDateTable
what I get back is JUST the rows which have data. Very a开发者_开发问答nnoying.
Thanks for any help you can give. I'm sure it's a simple solve, but it's beyond me.
This is some output where there is data from the userapplog;
Dates ElapsedSeconds
2011-05-17 00:00:00.000 5854
2011-05-18 00:00:00.000 5864
2011-05-21 00:00:00.000 4758
2011-05-22 00:00:00.000 8434
2011-05-23 00:00:00.000 2162
2011-05-25 00:00:00.000 491
2011-05-26 00:00:00.000 260
2011-05-28 00:00:00.000 216
If I run;
SELECT dates.Date as Dates
FROM
[fnDateTable] (dateadd("m",- 1,CONVERT(VARCHAR(10),GETDATE(),111)),CONVERT(VARCHAR(10),GETDATE(),111),'day') dates
I get
Dates
2011-04-29 00:00:00.000
2011-04-30 00:00:00.000
2011-05-01 00:00:00.000
2011-05-02 00:00:00.000
2011-05-03 00:00:00.000
2011-05-04 00:00:00.000
2011-05-05 00:00:00.000
.
.
Since you are using SQL Server 2008, you could try something like as described below using Common Table Expression (CTE)
and OUTER APPLY
.
Common Table Expressions
can be used to perform recursive functions. In this case, the CTE takes the initial date as the date 1 month prior from current date and then recursively loops by adding 1 day until the loop reaches the current date. Hence, forming the list of dates between two given dates. Using that CTE output, we can use OUTER APPLY
to find the sum of elapsed duration for a given date range.
You can also create the CTE as table-valued function and use it as shown under section Table-valued function. Both options provided below are same and they are separating the functionalities slightly differently.
Screenshot #1 shows the sample data stored in the table dbo.UsersAppLog and the screenshot #2 displays the output. The output will be same using both approaches because the only difference between below given options is one of them have part of the logic moved to a function. .
Option #1
Desired output without using table-valued function:
DECLARE @BeginDate DATETIME;
DECLARE @EndDate DATETIME;
SET @BeginDate = DATEADD(MONTH, -1, GETDATE());
SET @EndDate = GETDATE();
WITH CTE(DateRange) AS
(
SELECT @BeginDate AS DateRange
UNION ALL
SELECT DATEADD(DAY, 1, DateRange)
FROM CTE
WHERE DATEADD(DAY, 1, DateRange) <= @EndDate
)
SELECT DATEADD(DAY, 0, DATEDIFF(DAY, 0, CTE.DateRange)) AS DateRange
, COALESCE(UAL.ElapsedDuration, 0) AS ElapsedDuration
FROM CTE
OUTER APPLY (
SELECT SUM(ElapsedSeconds) ElapsedDuration
FROM dbo.UsersAppLog UAL
WHERE DATEDIFF(DAY, UAL.LoggedDate, CTE.DateRange) = 0
) UAL;
Option #2
Create script for Table-Valued function: .
CREATE FUNCTION [dbo].[fntDateRange]
(
@BeginDate DATETIME
, @EndDate DATETIME
)
RETURNS TABLE
AS
RETURN
(
WITH CTE(DateRange) AS
(
SELECT @BeginDate AS DateRange
UNION ALL
SELECT DATEADD(DAY, 1, DateRange)
FROM CTE
WHERE DATEADD(DAY, 1, DateRange) <= @EndDate
)
SELECT DATEADD(DAY, 0, DATEDIFF(DAY, 0, CTE.DateRange)) AS DateRange
FROM CTE
)
GO
Desired output using the table-valued function: .
SELECT RNG.DateRange
, COALESCE(UAL.ElapsedDuration, 0) AS ElapsedDuration
FROM dbo.fntDateRange(DATEADD(MONTH, -1, GETDATE()), GETDATE()) RNG
OUTER APPLY (
SELECT SUM(ElapsedSeconds) ElapsedDuration
FROM dbo.UsersAppLog UAL
WHERE DATEDIFF(DAY, UAL.LoggedDate, RNG.DateRange) = 0
) UAL;
Hope that helps.
Screenshot #1:
Screenshot #2:
精彩评论