Related
I want to get the total count of account numbers for each month in the year, but also give the user the choice to pick which months they want to see. I need to be able to see the amount of accounts that were closed between the beginning of the month of the start date and end of the month of the end date that they choose, or if the close date is null, but by each month.
If they choose just January, I want them to see the total of accounts for January 1st through January 31st, but if they pick January to December, I want them to see January 1st through December 31st, but I want the total per month.
I also want this to work for all years as well.
DECLARE #StartDate AS SMALLDATETIME
DECLARE #EndDate AS SMALLDATETIME
SET #StartDate = '01-01-2019'
SET #EndDate = '12-31-2019'
SELECT DISTINCT COUNT(a.ACCOUNTNUMBER) AS [December]
FROM dbo.ACCOUNT A
WHERE ((a.CLOSEDATE >= DATEADD(month, DATEDIFF(month, 0, #StartDate), 0)
AND a.CLOSEDATE <= EOMONTH(#EndDate))
OR a.CLOSEDATE IS NULL)
AND a.ProcessDate = CONVERT(VARCHAR(8), dateadd(day,-1, getdate()), 112)
This is my result now:
This is my desired result:
This should give the results you want but by rows not columns. I also had to make an assumption on what to use for date when closeddate is null. If you need more assistance or this isnt correct, we can work to solve it
DECLARE #StartDate AS SMALLDATETIME
DECLARE #EndDate AS SMALLDATETIME
SET #StartDate = '01-01-2019'
SET #EndDate = '12-31-2019'
SELECT DISTINCT COUNT(a.ACCOUNTNUMBER) AS [Accounts]
, DATENAME(m, Month(ISNULL(ClosedDate, a.ProcessDate = CONVERT(VARCHAR(8), dateadd(day, - 1, getdate()), 112)))) Monthof
FROM dbo.ACCOUNT A
WHERE
(
(
a.CLOSEDATE >= #StartDate
AND a.CLOSEDATE <= #EndDate
)
OR a.CLOSEDATE IS NULL
)
AND a.ProcessDate = CONVERT(VARCHAR(8), dateadd(day, - 1, getdate()), 112)
GROUP BY
DATENAME(m, Month(ISNULL(ClosedDate, a.ProcessDate = CONVERT(VARCHAR(8), dateadd(day, - 1, getdate()), 112))))
DATEDIFF(MONTH, '1/1/2014', '12/31/2014') + 1
This will give me 12.
What if I do this:
DATEDIFF(MONTH, '1/1/2014', '12/30/2014') + 1
It should give me 11 point something. How do I go about getting the exact number of months between these two dates? This needs to work for any combination of dates (any month of the year for any year).
You could do the calculation yourself in the following way:
DECLARE #startdate date = '1/1/2014'
DECLARE #enddate date = '12/30/2014'
DECLARE #startday int = DATEPART(DAY, #startdate)
DECLARE #endday int = DATEPART(DAY, #enddate)
DECLARE #startdateBase date = DATEADD(DAY, 1 - #startday, #startdate)
DECLARE #enddateBase date = DATEADD(DAY, 1 - #endday, #enddate)
DECLARE #deciMonthDiff float = CAST(DATEDIFF(MONTH, #startdate, #enddate) AS float) -
(#startday - 1.0) / DATEDIFF(DAY, #startdateBase, DATEADD(MONTH, 1, #startdateBase)) +
(#endday - 1.0) / DATEDIFF(DAY, #enddateBase, DATEADD(MONTH, 1, #enddateBase))
SELECT #deciMonthDiff
This calculates the #deciMonthDiff to be 11.935483870967.
Of course you can "inline" this as much as you want in order to avoid all the middle declarations.
The idea is to calculate the total month diff, then subtract the relative part of the first & last month depending on the actual day.
DATEDIFF with the MONTH option only returns an integer value. Using days or years would give you a rough "guesstimate" but still not exactly right (different number of days in a month/year so you can't just divide the days difference by 30).
If you want exact you would need to write your own function to walk through the months from start until end and account for how many days are in each month and get a percentage/factor of that month covered.
DECLARE #startdate date = '1/1/2014'
DECLARE #enddate date = '12/30/2014'
select case when DATEPART(DAY, #startdate) <= DATEPART(DAY, #enddate)
then datediff(month, #startdate, #enddate)
else datediff(month, #startdate, #enddate) -1
end
from Chris The Jedi of T-SQL
Having problems understanding how to get the Where clause to work with this date structure.
Here is the principal logic. I want data only from previous March 1 onward and ending on yesterdays date.
Example #1:
So today is Feb 13, 2015 This would mean I need data between (2014-03-01 and 2015-02-12)
Example #2:
Say today is March 20, 2015 This This would mean I need data between (2015-03-01 and 2015-03-19)
The where logic might work but it doesn't like to convert '3/1/' + year. But I'm not sure how else to express it. The first clause is fine its the Case section that is broken.
Query
SELECT [Request Date], [myItem]
FROM myTable
WHERE [Request Date] < CONVERT(VARCHAR(10), GETDATE(), 102)
AND [Request Date] = CASE WHEN
CONVERT(VARCHAR(10), GETDATE(), 102) <
CONVERT(VARCHAR(12), '3/1/' + DATEPART ( year , GETDATE()) , 114)
THEN [Request Date] > CONVERT(VARCHAR(12), '3/1/' + DATEPART ( year , GETDATE()-365) , 114)
ELSE [Request Date] > CONVERT(VARCHAR(12), '3/1/' + DATEPART ( year , GETDATE() , 114)
END
I have also tried
AND [Request Date] = CASE WHEN
CONVERT(VARCHAR(10), GETDATE(), 102) <
'3/1/' + CONVERT(VARCHAR(12), DATEPART ( YYYY , GETDATE()))
THEN [Request Date] > '3/1/' + CONVERT(VARCHAR(12), DATEPART ( YYYY , GETDATE()-364))
ELSE [Request Date] > '3/1/' + CONVERT(VARCHAR(12), DATEPART ( YYYY , GETDATE()))
END
Try this where clause.
WHERE [Request Date]
BETWEEN Cast(CONVERT(VARCHAR(4), Year(Getdate())-1)+ '-03-01' AS DATE)
AND Getdate() - 1
Here Cast(CONVERT(VARCHAR(4), Year(Getdate())-1)+ '-03-01' AS DATE) will fetch the first day of march month. With that add -1 year to get the starting point.
Getdate() - 1 will define the ending point
I'd prefer to create datetime variables for the #from - #to range but if this is for a view I guess you have to do it in the where clause.
SELECT [Request Date], [myItem]
FROM myTable
WHERE [Request Date] < cast(GETDATE() as date)
AND [Request Date] >= CASE WHEN
GETDATE() < CONVERT(datetime, '3/1/' + cast(Year(GETDATE()) as varchar(4)))
THEN CONVERT(datetime, '3/1/' + cast(Year(GETDATE()) - 1 as varchar(4)))
ELSE CONVERT(datetime, '3/1/' + cast(Year(GETDATE()) as varchar(4)))
END
Something like this? Always from Mar 1st onwards, previous year if it's now Mar 1 or earlier, and otherwise this year.
SELECT [Request Date], [myItem]
FROM myTable
WHERE [Request Date] >= dateadd(month, 2, DATEADD(year, DATEDIFF(year, 0, dateadd(month, -2, dateadd(day, -1, getdate()))), 0))
and [Request Date] < DATEADD(day, DATEDIFF(day, 0, getdate()), 0)
First it deducts one day, so that March 1 isn't taking the same year, then it deducts 2 months for getting those dates for previous year, then it rounds it to the year, and then it adds 2 months to get to Mar 1.
In Oracle, I'd compute the lower bound like this:
add_months( trunc( add_months( sysdate, -2 ), 'YEAR'), 2 )
In other words - subtract two months, round down to the start of the year, then add two months.
Hopefully, you can convert this to use appropriate TSQL functions.
Lets work with some test data:
DECLARE #MyDate DATETIME = '3/13/2015'
Going to declare some variable we will set:
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
In this code, I check to see if we are before or after march 1st, and if so we will use either the previous year, or this year for the starting point (fiscal year?)
SELECT #StartDate = CASE WHEN DATEPART(MONTH, #MyDate) < 3 THEN
DATEADD(MONTH, 2, DATEADD(YEAR, DATEDIFF(YEAR, 0, #MyDate) - 1, 0))
ELSE
DATEADD(MONTH, 2, DATEADD(YEAR, DATEDIFF(YEAR, 0, #MyDate), 0))
END,
#EndDate = DATEADD(DAY, DATEDIFF(DAY, 0, #MyDate), 0)
Here is the output:
SELECT #StartDate AS Start, #EndDate AS EndDate
Start EndDate
2015-03-01 00:00:00.000 2015-03-13 00:00:00.000
I would first create a fairly generic user-defined function that does what I need, thus:
create function dbo.start_of_fiscal_year
(
#today date ,
#fiscal_year_start_month int
)
returns date
as
begin
set #today = case coalesce(#today,'')
when '' then current_timestamp
else #today
end
declare #month_start date = dateadd(day,1-datepart(day,#today),#today)
declare #fiscal_month_number int = case sign( datepart(month,#month_start) - #fiscal_year_start_month )
when -1 then 13
else 1
end
+ ( datepart(month,#month_start) - #fiscal_year_start_month )
declare #fiscal_year_start date = dateadd(month,1-#fiscal_month_number,#month_start)
return #fiscal_year_start
end
go
Once you have that you can say things like
declare #today date = current_timetamp
declare #fy_start date = start_of_fiscal_year(#today,3)
select *
from dbo.foo t
where t.report_date >= #fy_start
and t.report_date < #today
or even
select fiscal_year = datepart(year,start_of_fiscal_year(t.report_date,3)) , count(*)
from dbo.foo t
group by datepart(year,start_of_fiscal_year(t.report_date,3))
Your lower bound should be this. You just need to offset the year when month is less than 3 (March).
dateadd(
yy,
year(current_timestamp) - 1900 + case when month(current_timestamp) < 3 then -1 else 0 end,
'19000301'
)
There's no reason to mess around with strings and this consolidates the logic very concisely. I'm also guessing that when current date is March 1 that you want to query the full previous year. So you'll want to adjust the test slightly.
case when (month(dateadd(dd, -1, current_timestamp)) < 3 ...
And just for fun:
dateadd(mm, (12-month(current_timestamp-1))/10*-12+2, cast(year(current_timestamp) as char(4)));
I have a problem with DATEDIFF function.
My date format is dd/mm/yyyy.
#START_DATE = 01/02/2004
#END_DATE = 29/01/2014
The query (DATEDIFF(DAY,#START_DATE,#END_DATE) / 365) return 10, but the number of correct years is 9. This happens because my query does not consider leap years.
What I can do to keep an accurate count?
Thanks.
I believe the following logic does what you want:
datediff(year,
#START_DATE - datepart(dayofyear, #START_DATE) + 1,
#END_DATE - datepart(dayofyear, #START_DATE) + 1
) as d2
Note: This treats that dates as datetime, because arithmetic is easier to express. You can also write this as:
datediff(year,
dateadd(day, - datepart(dayofyear, #START_DATE) + 1, #START_DATE),
dateadd(day, - datepart(dayofyear, #START_DATE) + 1, #END_DATE)
) as d2
The following query is a demonstration:
select datediff(year,
startdate - datepart(dayofyear, startdate) + 1,
enddate - datepart(dayofyear, startdate) + 1
) as d2
from (select cast('2004-02-01' as datetime) as startdate,
cast('2014-01-31' as datetime) as enddate
union all
select cast('2004-02-01' as datetime) as startdate,
cast('2014-02-01' as datetime) as enddate
) t
Technically there would be 365.242 days in a year, when accounting for leap years so:
FLOOR(DATEDIFF(day, #STARTDATE, #ENDDATE) / 365.242)
Should be more correct.
Test:
SELECT FLOOR(DATEDIFF(day, '1980-01-16','2015-01-15') / 365.242),
FLOOR(DATEDIFF(day, '1980-01-16','2015-01-16') / 365.242)
ResultSet:
--------------------------------------- ---------------------------------------
34 35
Cheers!
You can create a function to address that:
CREATE FUNCTION [dbo].[getYears]
(
#START_DATE datetime,
#END_DATE datetime
)
RETURNS int
AS
BEGIN
DECLARE #yrs int
SET #yrs =DATEDIFF(year,#START_DATE,#END_DATE)
IF (#END_DATE < DATEADD(year, #yrs, #START_DATE))
SET #yrs = #yrs -1
RETURN #yrs
END
Also check this
Count the number of leap days in end_date Deduct number of leap days in start_date. Deduct the answer from your DATEDIFF.
DECLARE
#START_DATE DATETIME = '2004-02-01',
#END_DATE DATETIME = '2014-01-29'
SELECT (
DATEDIFF(DAY,#START_DATE,#END_DATE)
- (
(CONVERT(INT,#END_DATE - 58) / 1461)
-
(CONVERT(INT,#START_DATE - 58) / 1461)
)
) / 365
-58 to ignore Jan and Feb 1900
/ 1461 being the number of days between leap years
Using SQL Server 2005 I have a field that contains a datetime value.
What I am trying to do is create 2 queries:
Compare to see if stored datetime is of the same month+year as current date
Compare to see if stored datetime is of the same year as current date
There is probably a simple solution but I keep hitting brick walls using various samples I can find, any thoughts?
Thanks in advance.
Compare the parts of the date:
WHERE YEAR( columnName ) = YEAR( getDate() )
While the other answers will work, they all suffer from the same problem: they apply a transformation to the column and therefore will never utilize an index on that column.
To search the date without a transformation, you need a couple built-in functions and some math. Example below:
--create a table to hold our example values
create table #DateSearch
(
TheDate datetime not null
)
insert into #DateSearch (TheDate)
--today
select getdate()
union all
--a month in advance
select dateadd(month, 1, getdate())
union all
--a year in advance
select dateadd(year, 1, getdate())
go
--declare variables to make things a little easier to see
declare #StartDate datetime, #EndDate datetime
--search for "same month+year as current date"
select #StartDate = dateadd(month, datediff(month, 0, getdate()), 0), #EndDate = dateadd(month, datediff(month, 0, getdate()) + 1, 0)
select #StartDate [StartDate], #EndDate [EndDate], TheDate from #DateSearch
where TheDate >= #StartDate and TheDate < #EndDate
--search for "same year as current date"
select #StartDate = dateadd(year, datediff(year, 0, getdate()), 0), #EndDate = dateadd(year, datediff(year, 0, getdate()) + 1, 0)
select #StartDate [StartDate], #EndDate [EndDate], TheDate from #DateSearch
where TheDate >= #StartDate and TheDate < #EndDate
What the statement does to avoid the transformations, is find all values greater-than or equal-to the beginning of the current time period (month or year) AND all values less-than the beginning of the next (invalid) time period. This solves our index problem and also mitigates any issues related to 3ms rounding in the DATETIME type.
SELECT * FROM atable
WHERE
YEAR( adate ) = YEAR( GETDATE() )
AND
MONTH( adate ) = MONTH( GETDATE() )
It sounds to me like DATEDIFF is exactly what you need:
-- #1 same month and year
SELECT *
FROM your_table
WHERE DATEDIFF(month, your_column, GETDATE()) = 0
-- #2 same year
SELECT *
FROM your_table
WHERE DATEDIFF(year, your_column, GETDATE()) = 0
The datepart function lets you pull the bits you need:
declare #d1 as datetime
declare #d2 as datetime
if datepart(yy, #d1) = datepart(yy, #d2) and datepart(mm, #d1) = datepart(mm, #d2) begin
print 'same'
end
You can use something like this
a)
select *
from table
where MONTH(field) = MONTH(GetDATE())
and YEAR(field) = YEAR(GetDATE())
b)
select *
from table
where YEAR(field) = YEAR(GetDATE())