March 21, 2006 at 1:31 pm
Would someone happen to have some T-SQL (preferrably a FUNCTION) to accomodate this? I need to return all rows from a single table where the Insert_Date = the following criteria:
select * from TAB_X where Insert_Date in
(last day of last year
or
quarter end date for each of last 2 quarters
or
last day of prior month)
Example:
If it's Oct 4th 2006, the query should return all rows w/ Insert_Date =
12/31/2005
06/30/2006
09/30/2006
March 22, 2006 at 1:36 am
Hi,
IMHO if you're doing such reports on regular basis, you should have auxiliary tables (like table Dates containing all dates 20 years back and 30 years forward). In such table, you can then once and for all time mark certain dates as relevant for certain report or simply mark end of month, end of quarter, state holidays, company holidays etc. This will allow you to JOIN to that table in queries, which should improve performance and allow queries that would be impossible without it (like precise calculation of workdays between two dates).
Without such table, you can do this (use this SQL in a procedure or function, or just as it is directly in the report - depends on you). Make sure you strip away the time portion from your Insert_Date... at least I suppose that Insert_Date has time entered. But even if it doesn't at the moment, it would be a good precaution to do so.
DECLARE @date datetime, @lastmonth datetime, @lastquarter datetime,
@prevquarter datetime, @lastyear datetime
SET @date = GETDATE() /*enter your date here*/
/*finds first day of this month and subtrats one day*/
SET @lastmonth = DATEADD(day, -1, CONVERT(char(6), @date, 112) + '01')
/*check whether last month was end of quarter; if not, loop back month by month till you get there*/
SET @lastquarter = @lastmonth
WHILE SUBSTRING(CONVERT(char(6),@lastquarter,112),5,2) NOT IN ('03','06','09','12')
BEGIN
SET @lastquarter = DATEADD(day, -1, CONVERT(char(6), @lastquarter, 112) + '01')
END
/*subtract another quarter - because of different number of days in months, add one day first, subtract 3 months and then add the day back*/
SET @prevquarter = DATEADD(month,-3,@lastquarter + 1) - 1
/*subtract one year*/
SET @lastyear = CONVERT(char(4), DATEADD(year,-1,@date),112)+ '1231'
/*just to check dates, whether it works well*/
select @date ,
@lastmonth as lastmonth,
@lastquarter as lastquarter,
@prevquarter as prevquarter,
@lastyear as lastyear
/*the actual select you need*/
select * from TAB_X where DATEADD(d, DATEDIFF(d, 0, Insert_Date), 0) in (@lastmonth,@lastquarter,@prevquarter,@lastyear)
March 22, 2006 at 7:04 am
Hello,
You could make 4 seperate functions which take a date as input parameter (e.g. @date) from the code I pasted below. I hope this is what you need .
--input argument
declare @date datetime
--testcases
set @date = '2006-10-04'
--set @date = '2006-08-04'
--set @date = '2006-06-04'
--set @date = '2006-01-01'
--set @date = '2006-02-28'
--set @date = '2006-12-31'
--local variables
declare @LastDayOfLastYear datetime, @PreviousQuarterEnd datetime, @SecondPreviousQuarterEnd datetime, @LastDayOfLastMonth datetime
--improve readability throughout code
set @LastDayOfLastYear = @date
set @PreviousQuarterEnd = @date
set @SecondPreviousQuarterEnd = @date
set @LastDayOfLastMonth = @date
--get last day of previous year
set @LastDayOfLastYear = dateadd( month, -( month(@LastDayOfLastYear) - 1), @LastDayOfLastYear)
set @LastDayOfLastYear = dateadd( day, -( day(@LastDayOfLastYear)), @LastDayOfLastYear)
--get last day of quarter before previous quarter
set @SecondPreviousQuarterEnd = dateadd( day, - day( min( @SecondPreviousQuarterEnd)), dateadd( month, -3, dateadd( month, - (( month( min( @SecondPreviousQuarterEnd)) - 1) % 3), min( @SecondPreviousQuarterEnd))))
--get last day of previous quarter
set @PreviousQuarterEnd = dateadd( day, - day( min( @PreviousQuarterEnd)), dateadd( month, - (( month( min( @PreviousQuarterEnd)) - 1) % 3), min( @PreviousQuarterEnd)))
--get last day of previous year
set @LastDayOfLastMonth = dateadd( day, -( day(@LastDayOfLastMonth)), @LastDayOfLastMonth)
--test results
select @LastDayOfLastYear, @SecondPreviousQuarterEnd, @PreviousQuarterEnd, @LastDayOfLastMonth
_____________________________________________________
Do not go past the mark you aimed for, but learn when to stop.
You can find me on LinkedIn.
I support The Programmer's Bill of Rights.
MCITP, MCDBA, MCSD
March 22, 2006 at 7:36 am
Erwin,
is there any reason why 4 functions would be more useful than one? Or, when we are at that, more useful than no function?
If you're thinking about re-using the separate functions in several places, well... why should anyone bother to create a function like this:
set @LastDayOfLastYear = dateadd( month, -( month(@LastDayOfLastYear) - 1), @LastDayOfLastYear)
set @LastDayOfLastYear = dateadd( day, -( day(@LastDayOfLastYear)), @LastDayOfLastYear)
if you can achieve the same much easier without UDF:
SELECT CONVERT(char(4), DATEADD(year,-1,@date),112)+ '1231'
March 22, 2006 at 7:43 am
These replies are near perfect for our solution. ! additional question. Using your SQL:
select dateadd(day,-day(min(getdate())),dateadd(month,-3,dateadd(month,-((month(min(getdate()))-1)%3),min(getdate()))))
HOW can I render this result w/ a TIME = 00:00:00.000?
Many many thx in advance!
March 22, 2006 at 7:53 am
hi Vladan,
Well, as you already stated, reusability is the main reason. Other than that I admit looking at you piece of code is easier to read, but I like to use specific datetime functions instead of conversions.
_____________________________________________________
Do not go past the mark you aimed for, but learn when to stop.
You can find me on LinkedIn.
I support The Programmer's Bill of Rights.
MCITP, MCDBA, MCSD
March 22, 2006 at 7:59 am
hi Bill
You could use a conversion (yeah, I know...) to obtain that result, like so:
select getdate(), convert( datetime, floor( convert( decimal(12, 4), getdate())))
_____________________________________________________
Do not go past the mark you aimed for, but learn when to stop.
You can find me on LinkedIn.
I support The Programmer's Bill of Rights.
MCITP, MCDBA, MCSD
March 22, 2006 at 8:02 am
Use CONVERT to format a date field for reporting.
CONVERT
(varchar, GETDATE(),1): 03/22/06
CONVERT(varchar, GETDATE(),2): 06.03.22
CONVERT(varchar, GETDATE(),3): 22/03/06
CONVERT(varchar, GETDATE(),4): 22.03.06
CONVERT(varchar, GETDATE(),5): 22-03-06
CONVERT(varchar, GETDATE(),6): 22 Mar 06
CONVERT(varchar, GETDATE(),7): Mar 22, 06
CONVERT(varchar, GETDATE(),8): 09:53:00
CONVERT(varchar, GETDATE(),9): Mar 22 2006 9:53:00:227AM
CONVERT(varchar, GETDATE(),10): 03-22-06
CONVERT(varchar, GETDATE(),11): 06/03/22
CONVERT(varchar, GETDATE(),12): 060322
CONVERT(varchar, GETDATE(),13): 22 Mar 2006 09:53:00:227
CONVERT(varchar, GETDATE(),14): 09:53:00:227
CONVERT(varchar, GETDATE(),20): 2006-03-22 09:54:58
CONVERT(varchar, GETDATE(),21): 2006-03-22 09:54:58.117
CONVERT(varchar, GETDATE(),22): 03/22/06 9:54:58 AM
CONVERT(varchar, GETDATE(),23): 2006-03-22
CONVERT(varchar, GETDATE(),24): 09:54:58
CONVERT(varchar, GETDATE(),25): 2006-03-22 09:54:58.117
CONVERT(varchar, GETDATE(),101): 03/22/2006
CONVERT(varchar, GETDATE(),102): 2006.03.22
CONVERT(varchar, GETDATE(),103): 22/03/2006
CONVERT(varchar, GETDATE(),104): 22.03.2006
CONVERT(varchar, GETDATE(),105): 22-03-2006
CONVERT(varchar, GETDATE(),106): 22 Mar 2006
CONVERT(varchar, GETDATE(),107): Mar 22, 2006
CONVERT(varchar, GETDATE(),108): 09:56:22
CONVERT(varchar, GETDATE(),109): Mar 22 2006 9:56:22:257AM
CONVERT(varchar, GETDATE(),110): 03-22-2006
CONVERT(varchar, GETDATE(),111): 2006/03/22
CONVERT(varchar, GETDATE(),112): 20060322
CONVERT(varchar, GETDATE(),113): 22 Mar 2006 09:56:22:257
CONVERT(varchar, GETDATE(),114): 09:56:22:257
CONVERT(varchar, GETDATE(),120): 2006-03-22 09:56:22
CONVERT(varchar, GETDATE(),121): 2006-03-22 09:56:22.257
CONVERT(varchar,GETDATE(),126): 2006-03-22T10:03:37.357
CONVERT(varchar,GETDATE(),127): 2006-03-22T10:03:37.357
CONVERT(varchar,GETDATE(),130): 22 ??? 1427 10:03:37:357AM
CONVERT(varchar,GETDATE(),131): 22/02/1427 10:03:37:357AM
March 22, 2006 at 8:04 am
You can create a date with zero time portion by using DATEADD(d, DATEDIFF(d, 0, @date), 0) - instead of @date, enter your date that you need to modify... or directly the expression you posted.
Results in SQL I posted are always without time and need no more manipulation.
Erwin, I can understand that UDF helps readability, but it is a question whether it does not degrade performance. This should be tested in the specific production database. And even if you write a function, I think it would be better to include one simple command into it than 2 more or less complicated ones that you posted.
March 22, 2006 at 8:15 am
Vladan,
You can use the functions to fill variables which you then use in the select statement, like you mentioned in your first post.
Complicated or not, I believe that your code runs equally fast as mine.
Btw, I like your piece of code you use the eliminate the time portion from a date
_____________________________________________________
Do not go past the mark you aimed for, but learn when to stop.
You can find me on LinkedIn.
I support The Programmer's Bill of Rights.
MCITP, MCDBA, MCSD
March 22, 2006 at 9:48 am
1 Final SQL adjustment needed.
This Statement returns the last DAY of the prior QTR. Needs to be adjusted to return a TIME = 00:00:00.000
SELECT
dateadd(day,-day(min(getdate())), dateadd(month,-((month(min(getdate()))-1)%3), min(getdate())))
thx
March 22, 2006 at 11:37 am
My alter ego pulled this together:
This Statement returns the last DAY of the prior QTR with TIME = 00:00:00.000
SELECT
CONVERT(DATETIME,FLOOR(CONVERT(FLOAT,DATEADD(DAY,-DAY(MIN(GETDATE())),DATEADD(MONTH,-((MONTH(MIN(GETDATE()))-1)%3),MIN(GETDATE()))))))
Viewing 12 posts - 1 through 11 (of 11 total)
You must be logged in to reply to this topic. Login to reply