SQL - Get Numerical Day of Month/Quarter - sql

Using SQL Server 2005:
How can I get the numerical day of the month and day of the quarter in a query?
DECLARE #DATE DATETIME
SET #DATE = GETDATE()
SELECT DATEPART(dy, #DATE) AS DayOfYear
--, <something> AS DayOfQuarter
--, <something> AS DayOfMonth
, DATEPART(dw, #DATE) AS DayOfWeek
Thanks in advance!

DECLARE #DATE DATETIME
SET #DATE = GETDATE()
SELECT DATEPART(dy, #DATE) AS DayOfYear
, DATEDIFF(d, DATEADD(qq, DATEDIFF(qq, 0, #DATE), 0), #DATE) + 1 AS DayOfQuarter
, DAY(#Date) AS DayOfMonth
, DATEPART(dw, #DATE) AS DayOfWeek

As for the day of quarter, this will demande a bit of further investigate on my side. Despite, I guess that for the day of month, this would simply be the date itself:
select DATEPART(D, #DATE)

SELECT
DATEPART(year, '12:10:30.123')
,DATEPART(month, '12:10:30.123')
,DATEPART(day, '12:10:30.123')
,DATEPART(dayofyear, '12:10:30.123')
,DATEPART(weekday, '12:10:30.123');

Related

Get last Friday's Date unless today is Friday using T-SQL

I'm trying to get the correct SQL code to obtain last Friday's date. A few days ago, I thought I had my code correct. But just noticed that it's getting last week's Friday date, not the last Friday. The day I'm writing this question is Saturday, 8/11/2012 # 12:23am. In SQL Server, this code is returning Friday, 8/3/2012. However, I want this to return Friday, 8/10/2012 instead. How can I fix this code? Since we're getting to specifics here, if the current day is Friday, then I want to return today's date. So if it were yesterday (8/10/2012) and I ran this code yesterday, then I would want this code to return 8/10/2012, not 8/3/2012.
SELECT DATEADD(DAY, -3, DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()), 0))
try this:
declare #date datetime;
set #date='2012-08-09'
SELECT case when datepart(weekday, #date) >5 then
DATEADD(DAY, +4, DATEADD(WEEK, DATEDIFF(WEEK, 0, #date), 0))
else DATEADD(DAY, -3, DATEADD(WEEK, DATEDIFF(WEEK, 0, #date), 0)) end
result:
2012-08-03
Example2:
declare #date datetime;
set #date='2012-08-10'
SELECT case when datepart(weekday, #date) >5 then
DATEADD(DAY, +4, DATEADD(WEEK, DATEDIFF(WEEK, 0, #date), 0))
else DATEADD(DAY, -3, DATEADD(WEEK, DATEDIFF(WEEK, 0, #date), 0)) end
result:
2012-08-10
Modular arithmetic is the most direct approach, and order of operations decides how Fridays are treated:
DECLARE #test_date DATETIME = '2012-09-28'
SELECT DATEADD(d,-1-(DATEPART(dw,#test_date) % 7),#test_date) AS Last_Friday
,DATEADD(d,-(DATEPART(dw,#test_date+1) % 7),#test_date) AS This_Friday
Use this :
SELECT DATEADD(day, (DATEDIFF (day, '19800104', CURRENT_TIMESTAMP) / 7) * 7, '19800104') as Last_Friday
None of that? Try this:
DECLARE #D DATE = GETDATE()
SELECT DATEADD(D,-(DATEPART(W,#D)+1)%7,#D)
A tested function which works no matter what ##DATEFIRST is set to.
-- ==============
-- fn_Get_Week_Ending_forDate
-- Author: Shawn C. Teague
-- Create date: 2017
-- Modified date:
-- Description: Returns the Week Ending Date on DayOfWeek for a given stop date
-- Parameters: DayOfWeek varchar(10) i.e. Monday,Tues,Wed,Friday,Sat,Su,1-7
-- DateInWeek DATE
-- ==============
CREATE FUNCTION [dbo].[fn_Get_Week_Ending_forDate] (
#DayOfWeek VARCHAR(10),#DateInWeek DATE)
RETURNS DATE
AS
BEGIN
DECLARE #End_Date DATE
,#DoW TINYINT
SET #DoW = CASE WHEN ISNUMERIC(#DayOfWeek) = 1
THEN CAST(#DayOfWeek AS TINYINT)
WHEN #DayOfWeek like 'Su%' THEN 1
WHEN #DayOfWeek like 'M%' THEN 2
WHEN #DayOfWeek like 'Tu%' THEN 3
WHEN #DayOfWeek like 'W%' THEN 4
WHEN #DayOfWeek like 'Th%' THEN 5
WHEN #DayOfWeek like 'F%' THEN 6
ELSE 7
END
select #End_Date =
CAST(DATEADD(DAY,
CASE WHEN (#DoW - (((##datefirst) + datepart(weekday, #DateInWeek)) % 7)) = 7
THEN 0
WHEN (#DoW - (((##datefirst) + datepart(weekday, #DateInWeek)) % 7)) < 0
THEN 7 - ABS(#DoW - (((##datefirst) + datepart(weekday, #DateInWeek)) % 7))
ELSE (#DoW - (((##datefirst) + datepart(weekday, #DateInWeek)) % 7) )
END
,#DateInWeek) AS DATE)
RETURN #End_Date
END
This will give you the Friday of Last week.
SELECT DATEADD(day, -3 - (DATEPART(dw, GETDATE()) + ##DATEFIRST - 2) % 7, GETDATE()) AS LastWeekFriday
This will give you last Friday's Date.
SELECT DATEADD(day, +4 - (DATEPART(dw, GETDATE()) + ##DATEFIRST-2) % 7, GETDATE()) AS LastFriday
select convert(varchar(10),dateadd(d, -((datepart(weekday, getdate()) + 1 + ##DATEFIRST) % 7), getdate()),101)
Following code can be use to return any last day by replacing #dw_wk, test case below use friday as asked in original questions
DECLARE #date SMALLDATETIME
,#dw_wk INT --last day of week required - its integer representation
,#dw_day int --current day integer reprsentation
SELECT #date='8/11/2012'
SELECT #dw_day=DATEPART(dw,#date)
SELECT #dw_wk=DATEPART(dw,'1/2/2015') --Just trying not to hard code 5 for friday, here we can substitute with any date which is friday
SELECT case when #dw_day<#dw_wk then DATEADD(DAY, #dw_wk-7-#dw_day,#date) else DATEADD(DAY,#dw_wk-#dw_day, #date) END
Here's an answer I found here adapted from MySQL to T-SQL that is a one liner using all basic arithmetic (no division or modulos):
SELECT DATEADD(d, 1 - datepart(weekday, dateadd(d, 2, GETDATE())), GETDATE())
You can do all sorts of combinations of this, like get next Friday's date unless today is Friday, or get last Thursday's date unless today is Thursday by just changing the 1 and the 2 literals in the command:
Get next Friday's date unless today is Friday
SELECT DATEADD(d, 7 - datepart(weekday, dateadd(d, 1, GETDATE())), GETDATE())
Get last Thursday's date unless today is Thursday
SELECT DATEADD(d, 1 - datepart(weekday, dateadd(d, 3, GETDATE())), GETDATE())
I have had this same issue, and created the following example to show how to do this and to make it flexible to use whichever day of the week you want. I have different lines in the SELECT statement, just to show what this is doing, but you just need the [Results] line to get the answer. I also used variables for the current date and the target day of the week, to make it easier to see what needs to change.
Finally, there is an example of results when you want to include the current date as a possible example or when you always want to go back to the previous week.
DECLARE #GetDate AS DATETIME = GETDATE();
DECLARE #Target INT = 6 -- 6 = Friday
SELECT
#GetDate AS [Current Date] ,
DATEPART(dw, #GetDate) AS [Current Day of Week],
#Target AS [Target Day of Week] ,
IIF(#Target = DATEPART(dw, #GetDate), 'Yes' , 'No') AS [IsMatch] ,
IIF(#Target = DATEPART(dw, #GetDate), 0 , ((7 + #Target - DATEPART(dw, #GetDate)) % 7) - 7) AS [DateAdjust] ,
------------------------------------------------------------------------------------------------------------------------------------------------
CAST(IIF(#Target = DATEPART(dw, #GetDate), #GetDate, DATEADD(d, (((7 + #Target - DATEPART(dw, #GetDate)) % 7) - 7), #GetDate)) AS DATE) AS [Result]
------------------------------------------------------------------------------------------------------------------------------------------------
;
SELECT
#GetDate AS [Current Date] ,
DATEPART(dw, #GetDate) AS [Current Day of Week],
#Target AS [Target Day of Week] ,
((7 + #Target - DATEPART(dw, #GetDate)) % 7) - 7 AS [DateAdjust] ,
------------------------------------------------------------------------------------------------------------------------------------------------
CAST(DATEADD(d, (((7 + #Target - DATEPART(dw, #GetDate)) % 7) - 7), #GetDate) AS DATE) AS [NOTIncludeCurrent]
------------------------------------------------------------------------------------------------------------------------------------------------
;
SELECT DECODE(TO_CHAR(SYSDATE,'DY'),'FRI',SYSDATE,NEXT_DAY(SYSDATE, 'FRI')-7) FROM dual;

Finding the list of people who have birthday this week

I am trying to list the people who have birthday this week with this code:
declare #START_DATE date;
set #START_DATE = DATEADD(dd, 1 - DATEPART(dw, getdate()), getdate())
declare #END_DATE date;
set #END_DATE = DATEADD(dd,6, #START_DATE)
set DATEFIRST 1
SELECT #START_DATE as StartDate, Personel.DogumTarihi , #END_DATE as EndDate
,[Adi]
,[Soyadi]
,[BirimAdi]
,[DogumTarihi]
,[MudurlukAdi]
,[Gorevi]
,[CepTelefonu]
,[EvTelefonu]
from Personel
where (
DATEPART(m, Personel.DogumTarihi) = DATEPART(m, #START_DATE)
and DATEPART(DAY, Personel.DogumTarihi) >= DATEPART(DAY, #START_DATE)
and DATEPART(DAY, Personel.DogumTarihi) <= DATEPART(DAY, #END_DATE)
)
OR (
DATEPART(m, Personel.DogumTarihi) = (DATEPART(m, #START_DATE)+ 1)
and DATEPART(DAY, Personel.DogumTarihi) <= DATEPART(DAY, #END_DATE)
)
First I set the start date and calculate the end date according to start date. Then I set Monday as the first day of week.
But everytime I run this, I receive a different Start date. I am quite new to Ms Sql Scripting, I may be doing sth wrong in the declarations but I couldn'd find it. Thanks in advance.
Try this:
SELECT DATEADD(WEEK, DATEDIFF(DAY, 0, GETDATE())/7, 0) FirstDayOfCurrentWeek,
DATEADD(YEAR, DATEDIFF(YEAR, DogumTarihi, GETDATE()), [DogumTarihi]) BirthdayThisYear,
DATEADD(WEEK, 1, DATEADD(WEEK, DATEDIFF(DAY, 0, GETDATE())/7, 0)) FirstDayOfNextWeek
,[Adi]
,[Soyadi]
,[DogumTarihi]
,[BirimAdi]
,[MudurlukAdi]
,[Gorevi]
,[CepTelefonu]
,[EvTelefonu]
FROM Personel
WHERE DATEADD(YEAR, DATEDIFF(YEAR, [DogumTarihi], GETDATE()), [DogumTarihi]) >= DATEADD(WEEK, DATEDIFF(DAY, 0, GETDATE())/7, 0)
AND
DATEADD(YEAR, DATEDIFF(YEAR, [DogumTarihi], GETDATE()), [DogumTarihi]) < DATEADD(WEEK, 1, DATEADD(WEEK, DATEDIFF(DAY, 0, GETDATE())/7, 0))
ok, one more attempt:
where
case when year(#START_DATE) = year(#END_DATE) THEN '1' ELSE CASE WHEN month(#birthdate) = 12 THEN '0' WHEN month(#birthdate) = 1 THEN '1' ELSE '9' END END
+ RIGHT('0' + CONVERT(varchar(2), MONTH(#birthdate)),2)
+ RIGHT('0' + CONVERT(varchar(2), DAY(#birthdate)),2)
between
case when year(#START_DATE) = year(#END_DATE) THEN '1' ELSE '0' END
+ RIGHT('0' + CONVERT(varchar(2), MONTH(#START_DATE)),2)
+ RIGHT('0' + CONVERT(varchar(2), DAY(#START_DATE)),2)
and
'1'
+ RIGHT('0' + CONVERT(varchar(2), MONTH(#END_DATE)),2)
+ RIGHT('0' + CONVERT(varchar(2), DAY(#END_DATE)),2)
sql should let you specify the week directly
DATEPART(ww,GETDATE())
or in oracle: to_char( mydate, 'ww' )
In order to cope with the my problem I revised the code above according to answers:
set DATEFIRST 1
declare #START_DATE date;
set #START_DATE = DATEADD(dd, 1 - DATEPART(dw, getdate()), getdate())
declare #END_DATE date;
set #END_DATE = DATEADD(dd,6, #START_DATE)
SELECT #START_DATE as StartDate,
(case when
(DATEPART(m, #START_DATE) = DATEPART(m, #END_DATE))
then
(case when (DATEPART(DAY, Personel.DogumTarihi) >= DATEPART(DAY, #START_DATE) and DATEPART(DAY, Personel.DogumTarihi) <= DATEPART(DAY, #END_DATE)) then Personel.DogumTarihi else 0 end)
else
(case when DATEPART(m, Personel.DogumTarihi) = DATEPART(m, #START_DATE)
then
(case when (DATEPART(DAY, Personel.DogumTarihi) >= DATEPART(DAY, #START_DATE)) then Personel.DogumTarihi else 0 end)
else
(case when (DATEPART(DAY, Personel.DogumTarihi) <= DATEPART(DAY, #END_DATE)) then Personel.DogumTarihi else 0 end)
end
)
end),
#END_DATE as EndDate, [TCKN]
,[Adi]
,[Soyadi]
,[BirimAdi]
,[DogumTarihi]
,[MudurlukAdi]
,[Gorevi]
,[CepTelefonu]
,[EvTelefonu]
,[VakifTelefonu]
from Personel where
DATEPART(m, #START_DATE) = DATEPART(m, #END_DATE)
OR DATEPART(m, Personel.DogumTarihi) = DATEPART(m, #START_DATE)
OR DATEPART(m, Personel.DogumTarihi) = DATEPART(m, #END_DATE)
Now it is taking the case where "the start and end date of the month are in the same week (like this week)" into account. It looks like it is bringing right results..
Let's have a try:
declare #today datetime
set #today = getdate()
-- erase the hours
set #today = dateadd(hh, -datepart(hh, #today), #today)
-- erase the minutes
set #today = dateadd(mi, -datepart(mi, #today), #today)
-- erase the seconds
set #today = dateadd(ss, -datepart(ss, #today), #today)
-- erase the milliseconds
set #today = dateadd(ms, -datepart(ms, #today), #today)
-- go to start of current week (sunday!)
set #today = dateadd(dd, 1-datepart(dw, #today), #today)
select * from MYTABLE
where DATECOL between
dateadd(yy, datepart(yy, DATECOL) - datepart(yy, #today), #today) and
dateadd(d, 7, dateadd(yy, datepart(yy, DATECOL) - datepart(yy, #today), #today))
Apparently SqlServer 2012 has a DATEFROMPARTS function, in 2005 we will have to use this roundabout way to trim a date.
To select a birthday, I exchange the "today's year" for the record's year. For the end-date of the range I add 7 days to that. Note that you want to search from sunday 0:00 to saturday 23:59.
This will probably still fail if halfway during the week a new year starts and the birthday you want is in the new year.

SQL Query for YTD, MTD, WTD totals

I would like this query to be able to automagically know today's date & time as well as the first of the year (or month) (or week)...
SELECT TicketID
FROM Ticket
WHERE (Ticket.DtCheckOut > '1/1/2011 12:00:00 AM')
AND (Ticket.DtCheckOut < '8/27/2011 12:00:00 AM')
I know it will use GETDATE() in some form, but you don't want to see what I've come up with, I promise!
Here is what I was reading on GETDATE() MDSN: GETDATE(Transact-SQL)
I looked around here and Google - and didn't find anything 'clean' - so any input would be awesome!
DECLARE #now DATETIME
SET #now = GETDATE()
SELECT
DATEADD(yy, DATEDIFF(yy, 0, #now), 0) AS FirstDayOfYear,
DATEADD(mm, DATEDIFF(mm, 0, #now), 0) AS FirstDayOfMonth,
DATEADD(DAY, -DATEDIFF(dd, ##DATEFIRST - 1, #now) % 7, #now) AS FirstDayOfWeek
##DATEFIRST is SQL Server's first day of the week, which defaults to Sunday if you are using U.S. English.
For the first day of the week it can be a bit tricky, depending on your actual requirements (whether you want to obey the user's datefirst setting or not, use Sunday regardless of the setting, etc.), see this question: Get first day of week in SQL Server. Here is one way to do it:
DECLARE
#today DATE = CURRENT_TIMESTAMP,
#y DATE,
#m DATE,
#w DATE;
SELECT
#y = DATEADD(YEAR, DATEDIFF(YEAR, 0, #today), 0),
#m = DATEADD(MONTH, DATEDIFF(MONTH, 0, #today), 0),
#w = DATEADD(DAY, 1-DATEPART(WEEKDAY, #today), #today);
SELECT
[First day of year] = #y,
[First day of month] = #m,
[First day of week] = #w;
Whichever one you are after, you can use in the query, e.g. for YTD you would use:
SELECT TicketCount = COUNT(TicketID)
FROM dbo.Ticket
WHERE DtCheckOut >= #y;
Don't really think you need the < portion of the query if you're trying to get a count up to right now. How many tickets will have been checked out tomorrow if I'm running the query today? If you want to protect yourself against that you can use:
SELECT COUNT(TicketID)
FROM dbo.Ticket
WHERE DtCheckOut >= #y
AND DtCheckOut < DATEADD(DAY, 1, #now);
You could make it a little more dynamic and pass in a parameter that says 'YTD', 'MTD' or 'WTD', e.g.
CREATE PROCEDURE dbo.CountTickets
#Range CHAR(3) = 'YTD'
AS
BEGIN
SET NOCOUNT ON;
-- you may want to handle invalid ranges, e.g.
IF #Range NOT IN ('YTD', 'MTD', 'WTD')
BEGIN
RAISERROR('Please enter a valid range.', 11, 1);
RETURN;
END
DECLARE
#today DATE = CURRENT_TIMESTAMP,
#start DATE;
SELECT
#start = CASE #range
WHEN 'YTD' THEN DATEADD(YEAR, DATEDIFF(YEAR, 0, #today), 0)
WHEN 'MTD' THEN DATEADD(MONTH, DATEDIFF(MONTH, 0, #today), 0)
WHEN 'WTD' THEN DATEADD(DAY, 1-DATEPART(WEEKDAY, #today), #today)
END;
SELECT
Range = #range,
TicketCount = COUNT(TicketID)
FROM dbo.Ticket
WHERE dtCheckOUt >= #start;
END
GO

How do I compare against the current week using SQL Server?

How do I compare an SQL Server date column against the current week?
For instance:
WHERE [Order].SubmittedDate = *THIS WEEK*
You could convert your date to a week number and compare this to the week number from the current date. Likewise, you'll need to compare the year as well, so that you don't get last year's weeks.
WHERE DATEPART(wk, [Order].SubmittedDate) = DATEPART(wk, GETDATE())
AND DATEPART(yy, [Order].SubmittedDate) = DATEPART(yy, GETDATE())
Assuming you are meaning always "this week" and there are no records with Submitted dates in the future, which I imagine could be the case you can do:
WHERE [Order].SubmittedDate >= DATEADD(dd, -(DATEPART(dw, GETDATE()) -1), GETDATE())
If dates do go into the future, the full restriction to this week is:
WHERE [Order].SubmittedDate >= DATEADD(dd, -(DATEPART(dw, GETDATE()) -1), GETDATE())
AND [Order].SubmittedDate < CAST(CONVERT(VARCHAR(10), DATEADD(dd, (8 - DATEPART(dw, GETDATE())), GETDATE()), 120) AS DATETIME)
I'd strongly recommend using a clause based on a start and end date like this, as it will allow efficient index use so should perform better.
Try this:
WHERE [Order].SubmittedDate BETWEEN
DATEADD(d, - DATEPART(dw, GETDATE()) + 1, GETDATE()) AND
DATEADD(d, 7 - DATEPART(dw, GETDATE()) , GETDATE())
Maybe this can run faster, as doesn't needs to be evaluated everytime:
DECLARE #StartDate DATETIME,
#EndDate DATETIME
SELECT #StartDate = DATEADD(d, - DATEPART(dw, GETDATE()) + 1, GETDATE()),
#EndDate = DATEADD(d, 8 - DATEPART(dw, GETDATE()) , GETDATE())
-- // Strip time part, so week starts on Sunday 00:00
SELECT #StartDate = CAST(FLOOR(CAST(#StartDate AS FLOAT)) AS DATETIME),
#EndDate = CAST(FLOOR(CAST(#EndDate AS FLOAT)) AS DATETIME)
...
WHERE [Order].SubmittedDate >= #StartDate AND [Order].SubmittedDate < #EndDate

Compare current date with stored datetime using month an year only

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())