August 18, 2007 at 8:35 pm
Let's see... here's some nicely formed test data that Gova provided...
DECLARE @myTable TABLE
(
DataDate DATETIME,
DataVale INT
)
INSERT @myTable
SELECT '07/01/2007', 100 UNION
SELECT '07/08/2007', 120 UNION
SELECT '07/15/2007', 150 UNION
SELECT '07/22/2007', 190 UNION
SELECT '07/29/2007', 210 UNION
SELECT '08/04/2007', 230 UNION
SELECT '08/11/2007', 240 UNION
SELECT '08/15/2007', 245 UNION
SELECT '08/18/2007', 255 UNION
SELECT '08/25/2007', 290
... and here's the requirements... I've highlighted the inputs in Bold blue and underlined the really importand part...
/* Result Expected is Datavalue as of that date for each day of the month as of that date */
/* Data is refreshed each Saturday and 15 of the month. */
/* Date is the parameter */
/* Create a report for the month of the date passed */
...and here's the sample output listed by Gova...
07/01/2007 100
07/02/2007 100
07/03/2007 100
07/04/2007 100
07/05/2007 100
07/06/2007 100
07/07/2007 100
07/08/2007 120
07/09/2007 120
07/10/2007 120
07/11/2007 120
07/13/2007 120
07/14/2007 120
07/15/2007 150
07/16/2007 150
07/17/2007 150
07/18/2007 150
07/19/2007 150
07/20/2007 150
07/21/2007 150
07/22/2007 190
07/23/2007 190
07/24/2007 190
07/25/2007 190
07/26/2007 190
07/27/2007 190
07/28/2007 190
07/29/2007 210
07/30/2007 210
07/31/2007 210
... Like I said, except for an error that Gova said was corrected, everything to define and resolve this problem was in the first post. I was actually getting ready to compliment Gova on defining the problem with such accuracy
--Jeff Moden
Change is inevitable... Change for the better is not.
August 18, 2007 at 10:09 pm
Whatever. It seemed all my suggestions were wrong, regardless of what was said. So it doesn't matter. Also, I did say use what I provided as a start, not a final solution.
August 18, 2007 at 11:14 pm
Gova,
Are you all set now?
--Jeff Moden
Change is inevitable... Change for the better is not.
August 21, 2007 at 10:33 am
Thanks Jeff that is perfect.
Unfortunately I had to create a user defined function for these values (Cannot use # tables so no identity function). I cannot add tables to database so the new table tally is not in my options. I managed to do something like this.
DECLARE @myTable TABLE ( DataDate DATETIME, DataVal INT )
INSERT @myTable
SELECT '07/01/2007', 100 UNION
SELECT '07/08/2007', 120 UNION
SELECT '07/15/2007', 150 UNION
SELECT '07/22/2007', 190 UNION
SELECT '07/29/2007', 210 UNION
SELECT '08/04/2007', 230 UNION
SELECT '08/11/2007', 240 UNION
SELECT '08/15/2007', 245 UNION
SELECT '08/18/2007', 255 UNION
SELECT '08/25/2007', 290
DECLARE @Ctr INT SET @Ctr = 1
DECLARE @pReportDate DATETIME SET @pReportDate = '08/15/2007'
DECLARE @Dates TABLE
(
DataDate DATETIME
)
WHILE @Ctr < 32 AND ISDATE(CONVERT(VARCHAR, DATEPART(MONTH, @pReportDate)) + '/' + CONVERT(VARCHAR, @Ctr) + '/' + CONVERT(VARCHAR, DATEPART(YEAR, @pReportDate))) = 1
BEGIN
INSERT @Dates
SELECT CONVERT(VARCHAR, DATEPART(MONTH, @pReportDate)) + '/' + CONVERT(VARCHAR, @Ctr) + '/' + CONVERT(VARCHAR, DATEPART(YEAR, @pReportDate))
SELECT @Ctr = @Ctr + 1
END
SELECT DT.DataDate,
MT.DataVal
FROM
(
SELECT D.DataDate, MAX(MT1.DataDate) MaxDate
FROM
@Dates D
JOIN
@myTable MT1
ON
D.DataDate >= MT1.DataDate
GROUP BY D.DataDate) DT
LEFT JOIN
@myTable MT
ON
DT.MaxDate = MT.DataDate
ORDER BY 1
Regards,
gova
August 21, 2007 at 2:27 pm
Just to throw in here, I would 1 probably do the extra work in the presentation side and not in the SQL Server but here is another option to do in SQL.
This function will be needed and is commonly how I deal with month ranges based on a date.
CREATE FUNCTION dbo.DateList (@pReportDate as DATETIME)
RETURNS TABLE
AS
RETURN(SELECT
CAST(dMonth + '/' + dDay + '/' + dYear as datetime) dDate
FROM
(SELECT
CAST(DATEPART(m,@pReportDate) as VARCHAR(2)) dMonth) A
CROSS JOIN
(
SELECT CAST((dDayA + dDayB) as VARCHAR(2)) dDay FROM (
SELECT 0 dDayA UNION ALL
SELECT 10 dDayA UNION ALL
SELECT 20 dDayA UNION ALL
SELECT 30 dDayA
) dA CROSS JOIN(
SELECT 0 dDayB UNION ALL
SELECT 1 dDayB UNION ALL
SELECT 2 dDayB UNION ALL
SELECT 3 dDayB UNION ALL
SELECT 4 dDayB UNION ALL
SELECT 5 dDayB UNION ALL
SELECT 6 dDayB UNION ALL
SELECT 7 dDayB UNION ALL
SELECT 8 dDayB UNION ALL
SELECT 9 dDayB
) dB
) B
CROSS JOIN
(SELECT
CAST(DATEPART(yyyy,@pReportDate) as VARCHAR(4)) dYear) C
WHERE
IsDate(dMonth + '/' + dDay + '/' + dYear) = 1)
GO
And assuming this is actually a table and not a table variable
CREATE TABLE myTable ( DataDate DATETIME, DataVal INT )
INSERT myTable
SELECT '07/01/2007', 100 UNION
SELECT '07/08/2007', 120 UNION
SELECT '07/15/2007', 150 UNION
SELECT '07/22/2007', 190 UNION
SELECT '07/29/2007', 210 UNION
SELECT '08/04/2007', 230 UNION
SELECT '08/11/2007', 240 UNION
SELECT '08/15/2007', 245 UNION
SELECT '08/18/2007', 255 UNION
SELECT '08/25/2007', 290
I would then do this
SET NOCOUNT ON
SELECT
A.DataDate,
X.DataVal
FROM
(
SELECT
D.dDate DataDate,
MAX(MT.DataDate) qDate
FROM
dbo.DateList('08/15/2007') D
INNER JOIN
myTable MT
ON
MT.DataDate <= D.dDate
GROUP BY
D.dDate
) A
INNER JOIN
myTable X
ON
A.qDate = X.DataDate
August 21, 2007 at 2:42 pm
You can use the date table function on this link to load a date table, or you can use it directly in your query.
Date Table Function F_TABLE_DATE:
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=61519
select
DATE
from
F_TABLE_DATE('20070701','20070731')
August 21, 2007 at 3:34 pm
Thanks for the feedback, Gova.
Michael's suggestion of using his very fast date generator function would do nicely.
Strange to have a DBA that won't allow adding helper tables to a DB ...
--Jeff Moden
Change is inevitable... Change for the better is not.
August 22, 2007 at 8:35 am
Although I think Michael has a very good method the problem is that it generates a lot of extra information that would be better compartmentalized into multiple functions rather than one. If you needed a range I would do something like this instead
CREATE FUNCTION dbo.RangeDateList (@rangeStart as DATETIME, @rangeEnd as DATETIME)
RETURNS @RangeList TABLE (dDate DATETIME primary key clustered)
AS
BEGIN
DECLARE @Years TABLE (dYear varchar(4))
DECLARE @cnt int,
@cntStop int
SET @cnt = DATEPART(yyyy,@rangeStart)
SET @cntStop = DATEPART(yyyy,@rangeEnd)
WHILE @cnt <= @cntStop
BEGIN
INSERT INTO @Years (dYear) VALUES (CAST(@cnt as VARCHAR(4))) -- Always be explicit to ensure compatibility.
SET @cnt = @cnt + 1
END
INSERT @RangeList SELECT
CAST(dMonth + '/' + dDay + '/' + dYear as datetime) dDate
FROM
(
SELECT '01' dMonth UNION ALL
SELECT '02' dMonth UNION ALL
SELECT '03' dMonth UNION ALL
SELECT '04' dMonth UNION ALL
SELECT '05' dMonth UNION ALL
SELECT '06' dMonth UNION ALL
SELECT '07' dMonth UNION ALL
SELECT '08' dMonth UNION ALL
SELECT '09' dMonth UNION ALL
SELECT '10' dMonth UNION ALL
SELECT '11' dMonth UNION ALL
SELECT '12' dMonth
) A
CROSS JOIN
(
SELECT CAST((dDayA + dDayB) as VARCHAR(2)) dDay FROM (
SELECT 0 dDayA UNION ALL
SELECT 10 dDayA UNION ALL
SELECT 20 dDayA UNION ALL
SELECT 30 dDayA
) dA CROSS JOIN(
SELECT 0 dDayB UNION ALL
SELECT 1 dDayB UNION ALL
SELECT 2 dDayB UNION ALL
SELECT 3 dDayB UNION ALL
SELECT 4 dDayB UNION ALL
SELECT 5 dDayB UNION ALL
SELECT 6 dDayB UNION ALL
SELECT 7 dDayB UNION ALL
SELECT 8 dDayB UNION ALL
SELECT 9 dDayB
) dB
) B
CROSS JOIN
(SELECT dYear FROM @Years) C
WHERE
IsDate(dMonth + '/' + dDay + '/' + dYear) = 1 AND
CAST((dMonth + '/' + dDay + '/' + dYear) AS DATETIME) BETWEEN @rangeStart AND @rangeEnd
RETURN
END
GO
The big issue I see is response time. I tried Michael's function with a span of 100 years and found it take 2 minutes 32 seconds on my machine and my version only took 16 sec. Even when I add in to the query the extra pieces he returns on my query
Psuedo...
SELECT ... FROM dbo.RangeDateList('19500101','20491231')
I still came in at 1 minute 53 sec. I would say just be carefull not to overcomplicate the simplest need by coding it to death. Remember to always keep in mind the KISS method.
August 22, 2007 at 11:44 am
Here's a solution without UDFs, but it does take a Tally (number) table. Which, btw, mine starts at zero.
DECLARE @myTable TABLE ( DataDate DATETIME, DataVale INT ); INSERT @myTable SELECT '07/01/2007', 100 UNION all SELECT '07/08/2007', 120 UNION all SELECT '07/15/2007', 150 UNION all SELECT '07/22/2007', 190 UNION all SELECT '07/29/2007', 210 UNION all SELECT '08/04/2007', 230 UNION all SELECT '08/11/2007', 240 UNION all SELECT '08/15/2007', 245 declare @SelectDate datetime, @StartDate datetime; set @SelectDate = '07/31/2007'; -- Simulate an input parameter set @StartDate = DateAdd( mm, DateDiff( mm, 0, @SelectDate), 0); -- Truncate to first day of month select DateAdd( dd, DateDiff( dd, 0, @StartDate) + T.Zn, 0) as [Date], (select top 1 DataVale from @MyTable where DataDate between @StartDate and DateAdd( dd, DateDiff( dd, 0, @StartDate) + T.Zn, 0) order by DataDate desc) as [Total] from Utility.dbo.Tally T where T.Zn < DatePart(dd, @SelectDate);
The output of the above (for all of Aug)(edited for brevity) is:
Date Total 2007-07-01 00:00:00.000100 ... 2007-07-07 00:00:00.000100 2007-07-08 00:00:00.000120 ... 2007-07-14 00:00:00.000120 2007-07-15 00:00:00.000150 ... 2007-07-21 00:00:00.000150 2007-07-22 00:00:00.000190 ... 2007-07-28 00:00:00.000190 2007-07-29 00:00:00.000210 2007-07-30 00:00:00.000210 2007-07-31 00:00:00.000210
Change the target date to 7/15/2007 and this is the result:
Date Total 2007-07-01 00:00:00.000100 ... 2007-07-07 00:00:00.000100 2007-07-08 00:00:00.000120 ... 2007-07-14 00:00:00.000120 2007-07-15 00:00:00.000150
Tomm Carr
--
Version Normal Form -- http://groups.google.com/group/vrdbms
Viewing 9 posts - 16 through 23 (of 23 total)
You must be logged in to reply to this topic. Login to reply