Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
Author |
Topic |
R
Constraint Violating Yak Guru
328 Posts |
Posted - 2011-05-11 : 05:20:17
|
I have a stored procedure that searches for login dates for a client. These are then put into a table variable. Finally, the results are selected and grouped by month-year. So this statement:SELECT COUNT(*) AS totals, CAST(year([loginDate]) as nvarchar) + '-' + CAST(month([loginDate]) as nvarchar) as colNameFROM @tmpTable GROUP BY datename(month, [loginDate])+' '+CAST(Year(loginDate) AS nvarchar), month([loginDate]), year([loginDate])ORDER BY year(loginDate), month(loginDate) produces this result:totals colName-----------------64 2006-12139 2007-152 2007-3121 2007-4 You can see that because there were no logins during 2007-2 that this month is missing from the results. Is there a quick way to join the table variable to a statement that finds the min/max dates and simply 'fills in' the missing months, so I can get...totals colName-----------------64 2006-12139 2007-10 2007-2 <<-- 'filled in'52 2007-3121 2007-4 Here's hoping...  |
|
webfred
Master Smack Fu Yak Hacker
8781 Posts |
|
khtan
In (Som, Ni, Yak)
17689 Posts |
Posted - 2011-05-11 : 05:55:48
|
you will need to generate the lists of possible dates and then LEFT JOIN to your table.If you have a number / tally tabledeclare @start_date datetime, @end_date datetimeselect @start_date = '2006-01-01', @end_date = '2007-12-31'; with dates as( select date_start = dateadd(month, n.number, @start_date), date_end = dateadd(month, n.number + 1, @start_date) from numbers n where n.number between 0 and datediff(month, @start_date, @end_date))select isnull(count(t.loginDate), 0) as totals, convert(varchar(7), d.date_start, 121)from dates d left join @tmpTable t on d.date_start <= t.loginDate and d.date_end > t.loginDategroup by convert(varchar(7), d.date_start, 121) if you do not have one, you can use F_TABLE_NUMBER_RANGE or F_TABLE_DATE KH[spoiler]Time is always against us[/spoiler] |
 |
|
webfred
Master Smack Fu Yak Hacker
8781 Posts |
|
R
Constraint Violating Yak Guru
328 Posts |
Posted - 2011-05-11 : 06:29:16
|
Okay thanks for your posts. I had a go at trying to solve this in a different way...I thought if I get the MIN login date, and the MAX login date, I could loop through these (adding a month each time) and put those values into a secondary table variable. Then, simply join the second table in my original statement.The problem however is that my WHILE loop is failing (it never actually starts to loop, and just skips). Can anyone please verify that the syntax is correct please, or can anyone see what I've done wrong...?!?DECLARE @monthsYears TABLE (monthYear nvarchar(10))DECLARE @mMin INTDECLARE @mMax INTDECLARE @yMin INTDECLARE @yMax INTDECLARE @minDate datetimeDECLARE @maxDate datetimeSET @minDate = (SELECT MIN([loginDate]) FROM @tmpTable)SET @maxDate = (SELECT MAX([loginDate]) FROM @tmpTable)SET @mMin = (SELECT MIN(MONTH(@minDate)))SET @yMin = (SELECT MIN(YEAR(@minDate)))SET @mMax = (SELECT MAX(MONTH(@maxDate)))SET @yMax = (SELECT MAX(YEAR(@maxDate)))PRINT @mMin -- '6'PRINT @yMin -- '2006'PRINT @mMax -- '5'PRINT @yMax -- '2011' WHILE (@mMin <= @mMax AND @yMin <= @yMax) BEGIN -- ...............This never starts...............! INSERT INTO @monthsYears ( monthYear ) VALUES ( cast(@mMin AS nvarchar) + '-' + cast(@yMin AS nvarchar) ) SET @mMin = @mMin + 1 IF @mMin > 12 BEGIN SET @yMin = @yMin + 1 SET @mMin = 1 END ENDSELECT * FROM @monthsYears -- No rows! |
 |
|
khtan
In (Som, Ni, Yak)
17689 Posts |
Posted - 2011-05-11 : 08:21:34
|
because you are getting the min & max of the month separately. So if you have logindate like 2010-12-02 and 2011-02-03 you will not get any result at all.You should get the minimum date and maximum date and then loop on thatselect @minDate = MIN([loginDate]), @maxDate = MAX([loginDate])FROM @tmpTablewhile @minDate <= @maxDatebegin INSERT INTO @monthsYears select right(convert(varchar(10), @minDate, 105), 7) select @minDate = dateadd(month, 1, @minDate)endSELECT * FROM @monthsYears KH[spoiler]Time is always against us[/spoiler] |
 |
|
R
Constraint Violating Yak Guru
328 Posts |
Posted - 2011-05-11 : 08:32:39
|
Hi khtan you just beat me there...I had a play around and did this instead, although I'm not sure how effecient it is...DECLARE @monthsYears TABLE (monthYear nvarchar(10))DECLARE @mMin INTDECLARE @mMax INTDECLARE @yMin INTDECLARE @yMax INTDECLARE @minDate datetimeDECLARE @maxDate datetimeSET @minDate = (SELECT MIN([loginDate]) FROM @tmpTable)SET @maxDate = (SELECT MAX([loginDate]) FROM @tmpTable)SET @mMin = (SELECT MIN(MONTH(@minDate)))SET @yMin = (SELECT MIN(YEAR(@minDate)))SET @mMax = (SELECT MAX(MONTH(@maxDate)))SET @yMax = (SELECT MAX(YEAR(@maxDate)))PRINT @mMin -- '6'PRINT @yMin -- '2006'PRINT @mMax -- '5'PRINT @yMax -- '2011' DECLARE @dateReached bitSET @dateReached = 0WHILE @dateReached = 0 BEGIN IF @yMin >= @yMax AND @mMin >= @mMax BEGIN SET @dateReached = 1 END INSERT INTO @monthsYears ( monthYear ) VALUES ( cast(@yMin AS nvarchar) + '-' + cast(@mMin AS nvarchar) ) SET @mMin = @mMin + 1 IF @mMin > 12 BEGIN SET @yMin = @yMin + 1 SET @mMin = 1 END ENDSELECT * FROM @monthsYears |
 |
|
R
Constraint Violating Yak Guru
328 Posts |
Posted - 2011-05-11 : 08:39:53
|
quote: Originally posted by khtan because you are getting the min & max of the month separately. So if you have logindate like 2010-12-02 and 2011-02-03 you will not get any result at all.
I tried your suggestion out but there was a problem. If the DAY integer of the end date is less than the DAY integer of the start date, it misses off the last month.DECLARE @monthsYears TABLE (monthYear nvarchar(10))DECLARE @minDate datetimeDECLARE @maxDate datetimeSET @minDate = (SELECT MIN([loginDate]) FROM @tmpTable)SET @maxDate = (SELECT MAX([loginDate]) FROM @tmpTable)WHILE @minDate <= @maxDate BEGIN INSERT INTO @monthsYears ( monthYear ) VALUES ( cast(YEAR(@minDate) AS nvarchar) + '-' + cast(MONTH(@minDate) AS nvarchar) ) SET @minDate = DATEADD(Month, 1, @minDate) END SELECT * FROM @monthsYears Is there a way to modify the start date to make it the first day of that respective month, and modify the end date to make it the last day of that month? I think this would get around that problem... |
 |
|
khtan
In (Som, Ni, Yak)
17689 Posts |
Posted - 2011-05-11 : 08:56:45
|
quote: I tried your suggestion out but there was a problem. If the DAY integer of the end date is less than the DAY integer of the start date, it misses off the last month.
true. i missed that.this will convert the day to 1st of the month and over come that.select @minDate = dateadd(day, datediff(day, 0, MIN([loginDate])), 0), @maxDate = dateadd(day, datediff(day, 0, MAX([loginDate])), 0)FROM @tmpTable KH[spoiler]Time is always against us[/spoiler] |
 |
|
R
Constraint Violating Yak Guru
328 Posts |
Posted - 2011-05-11 : 09:06:55
|
quote: Originally posted by khtanthis will convert the day to 1st of the month and over come that.select @minDate = dateadd(day, datediff(day, 0, MIN([loginDate])), 0), @maxDate = dateadd(day, datediff(day, 0, MAX([loginDate])), 0)FROM @tmpTable
Hmmmm. Not quite sure I understand what you've done there, however, it is still missing off the last month! |
 |
|
khtan
In (Som, Ni, Yak)
17689 Posts |
Posted - 2011-05-11 : 09:14:37
|
very sorry, should by month instead of dayselect @minDate = dateadd(month, datediff(month, 0, MIN([loginDate])), 0), @maxDate = dateadd(month, datediff(month, 0, MAX([loginDate])), 0)FROM @tmpTable KH[spoiler]Time is always against us[/spoiler] |
 |
|
R
Constraint Violating Yak Guru
328 Posts |
Posted - 2011-05-11 : 09:22:27
|
LOL not a problem. Works like a charm.I don't suppose I could ask you to explain the logic of the statement please? Thanks! |
 |
|
khtan
In (Som, Ni, Yak)
17689 Posts |
Posted - 2011-05-11 : 10:21:51
|
sure1. this "datediff(month, 0, <date>)" = <1> will give you the different in terms of month between the <date> and 0 which is 1900-01-01.2. dateadd(month, < 1 >, 0) adding the number of month to 1900-01-01 will give you back the date with day = 13. The end result is you will always get 1st of the month of the input <date>. KH[spoiler]Time is always against us[/spoiler] |
 |
|
khtan
In (Som, Ni, Yak)
17689 Posts |
Posted - 2011-05-11 : 10:23:19
|
similarly,if you have a date with time (eg getdate()), you can use similar techniquetryselect dateadd(day, datediff(day, 0, getdate()), 0), dateadd(month, datediff(month, 0, getdate()), 0), dateadd(year, datediff(year, 0, getdate()), 0) KH[spoiler]Time is always against us[/spoiler] |
 |
|
R
Constraint Violating Yak Guru
328 Posts |
Posted - 2011-05-11 : 10:58:39
|
That's great. Thank you very much! |
 |
|
|
|
|
|
|