|
|
|
SSC Veteran
      
Group: General Forum Members
Last Login: Monday, October 22, 2012 7:08 AM
Points: 232,
Visits: 112
|
|
|
|
|
|
Forum Newbie
      
Group: General Forum Members
Last Login: Friday, April 12, 2013 8:13 AM
Points: 5,
Visits: 292
|
|
How about set-based approach:
SET DATEFIRST 1 ;WITH days(Date) AS ( --Get 13th of this month SELECT CAST(CAST(YEAR(GETDATE()) AS VARCHAR(4)) + '-' + CAST(MONTH(GETDATE()) AS VARCHAR(2)) + '-13' AS DATETIME) UNION ALL --Get 13th of next months SELECT DATEADD(MONTH, 1, Date) FROM days ) SELECT TOP 1 * FROM days WHERE DATEPART(dw, Date) = 5 AND Date > GETDATE()
|
|
|
|
|
SSC Veteran
      
Group: General Forum Members
Last Login: Monday, October 22, 2012 7:08 AM
Points: 232,
Visits: 112
|
|
Good one! :) but I am not much comfortable with UNION ALL. what you say?
Thanks,
Ashka Modi Software Engineer || credEcard Technologies (india) Pvt. Ltd.
|
|
|
|
|
Forum Newbie
      
Group: General Forum Members
Last Login: Friday, April 12, 2013 8:13 AM
Points: 5,
Visits: 292
|
|
| "UNION ALL" is a requirement in CTE
|
|
|
|
|
SSC Veteran
      
Group: General Forum Members
Last Login: Monday, October 22, 2012 7:08 AM
Points: 232,
Visits: 112
|
|
SET DATEFIRST 1 ;WITH days(Date) AS ( --Get 13th of this month SELECT CAST(CAST(YEAR(GETDATE()) AS VARCHAR(4)) + '-' + CAST(MONTH(GETDATE()) AS VARCHAR(2)) + '-13' AS DATETIME) UNION ALL --Get 13th of next months SELECT DATEADD(MONTH, 1, Date) FROM days ) SELECT * FROM days SELECT TOP 1 * FROM days WHERE DATEPART(dw, Date) = 5 AND Date > GETDATE() Have you check this? check Execution plan also.
Thanks,
Ashka Modi Software Engineer || credEcard Technologies (india) Pvt. Ltd.
|
|
|
|
|
Forum Newbie
      
Group: General Forum Members
Last Login: Friday, April 12, 2013 8:13 AM
Points: 5,
Visits: 292
|
|
I'm not sure what you mean.
"SELECT * FROM days" will fail because of recursion limit. But original idea was to get only the first Friday, the 13th. As there is always at least one such day in a year, there will be no more than 23 iterations.
Is there something wrong with execution plan?
Sorry for asking, but are you familiar with common table expressions (CTE)?
|
|
|
|
|
Ten Centuries
      
Group: General Forum Members
Last Login: Wednesday, May 15, 2013 3:57 AM
Points: 1,163,
Visits: 2,600
|
|
Another set based solution, this time using the good old Tally table. ((c) Jeff Moden et al. 19xx-2009)
SELECT TOP 1 DATEADD(dd,N-1,GETDATE()) FROM Tally WHERE n < 366 --== One years worth of days AND DAY(DATEADD(dd,N-1,GETDATE())) = 13 AND --== --== Using @@DATEFIRST and the modulus operator we don't need to change or --== assume anything about the current DATEFIRST setting --== (@@DATEFIRST + DATEPART(dw,DATEADD(dd,N-1,GETDATE()))) %7 = 6 ORDER BY N The execution plan for this indicates 100% of the query is spent doing a clustered index seek (nice!). That's if you build your tally table with a clustered index of course, as demonstrated in Jeff's tally table article.
And, as I indicated in the comments, you don't need to mess about with the DATEFIRST setting.
-- Nigel Useful Links: How to post data/code on a forum to get the best help The "Numbers" or "Tally" Table - Jeff Moden
|
|
|
|
|
SSC-Dedicated
           
Group: General Forum Members
Last Login: Today @ 6:23 AM
Points: 32,903,
Visits: 26,784
|
|
Rimvydas Gurskis (8/27/2009)
How about set-based approach: SET DATEFIRST 1 ;WITH days(Date) AS ( --Get 13th of this month SELECT CAST(CAST(YEAR(GETDATE()) AS VARCHAR(4)) + '-' + CAST(MONTH(GETDATE()) AS VARCHAR(2)) + '-13' AS DATETIME) UNION ALL --Get 13th of next months SELECT DATEADD(MONTH, 1, Date) FROM days ) SELECT TOP 1 * FROM days WHERE DATEPART(dw, Date) = 5 AND Date > GETDATE()
Correct me if I'm wrong, but that appears to be a recursive CTE .... which ISN'T set based at all. In fact, recurrsive CTE's are sometimes slower than a memory only While Loop.
--Jeff Moden "RBAR is pronounced "ree-bar" and is a "Modenism" for "Row-By-Agonizing-Row".
First step towards the paradigm shift of writing Set Based code: Stop thinking about what you want to do to a row... think, instead, of what you want to do to a column."
For better, quicker answers on T-SQL questions, click on the following... http://www.sqlservercentral.com/articles/Best+Practices/61537/
For better answers on performance questions, click on the following... http://www.sqlservercentral.com/articles/SQLServerCentral/66909/
|
|
|
|
|
SSC Rookie
      
Group: General Forum Members
Last Login: Thursday, April 11, 2013 1:43 PM
Points: 34,
Visits: 115
|
|
I agree with Rimvydas' approach. And for performance concerns on CTEs on this particular problem, this gives all the years from 1753 to 9999 that have 3 Friday the thirteenths. It runs in about 2 to 3 seconds on my small test machine.
with thirteen (thedate) as( select cast('01/13/1753' as datetime) as thedate union all select DATEADD(mm, 1, thedate) from thirteen where thedate < '01/01/9999' ) select year(thedate) yr, count(*) cnt from thirteen where DATENAME(dw, thedate) = 'Friday' group by year(thedate) having count(*) = 3 OPTION (MAXRECURSION 0)
|
|
|
|
|
Ten Centuries
      
Group: General Forum Members
Last Login: Wednesday, May 15, 2013 3:57 AM
Points: 1,163,
Visits: 2,600
|
|
Bill Coale (8/27/2009) I agree with Rimvydas' approach. And for performance concerns on CTEs on this particular problem, this gives all the years from 1753 to 9999 that have 3 Friday the thirteenths. It runs in about 2 to 3 seconds on my small test machine.
If your concerned with performance I'd go for the tally table approach, The following executes in around 100ms on my machine.
SELECT YEAR(DATEADD(mm,N-1,'17530113')), COUNT(*) FROM dbo.Tally WHERE N < DATEDIFF(mm,'17530113','99990101') AND DATENAME(dw, DATEADD(mm,N-1,'17530113')) = 'Friday' GROUP BY YEAR(DATEADD(mm,N-1,'17530113')) HAVING count(*) = 3 ORDER BY YEAR(DATEADD(mm,N-1,'17530113'))
-- Nigel Useful Links: How to post data/code on a forum to get the best help The "Numbers" or "Tally" Table - Jeff Moden
|
|
|
|