SQL Server : selecting 'WEEKDAY' part by passing date in 'ddd' format - sql-server

How I can retrieve 'WEEKDAY' part by passing 'ddd' format in SQL Server?
For example in if I pass 'tue' and the response will be 3, beacuse
1 - Sunday
2 - Monday
3 - Tuesday
... like that.
I get the 'WEEKDAY' of current date by executing following query.
select DATEPART(WEEKDAY, GETDATE())

This will return the day number for the given short day name honouring the current DATEFIRST setting.
--Example day name
DECLARE #Day CHAR(3) = 'Tue'
SELECT
DATEPART(WEEKDAY,DATEADD(DAY, Number, GETDATE())) DayNumber
FROM
master..spt_values N
WHERE
N.type = 'P' AND N.number BETWEEN 1 AND 7
AND DATENAME(WEEKDAY,DATEADD(DAY, Number, GETDATE())) LIKE #Day+'%'

You can try similar to this
SELECT *
FROM (
SELECT 1 PK ,'Sunday' Value UNION
SELECT 2,'Monday' UNION
SELECT 3,'Tuesday' UNION
...
SELECT 7,'Saturday'
) T WHERE T.[Value] LIKE '%tue%'

Try this:
SELECT datepart(weekday,getdate()), datename(dw, getdate())
This will return the weekday and name of that day considering ISO_WEEK rule
More detail here

this will give you the weekday no that is not dependant on ##datefirst or langauge setting
select [weekday] = case #weekday_name
when 'Sun' then (7 - ##datefirst + 0) % 7 + 1
when 'Mon' then (7 - ##datefirst + 1) % 7 + 1
when 'Tue' then (7 - ##datefirst + 2) % 7 + 1
when 'Wed' then (7 - ##datefirst + 3) % 7 + 1
when 'Thu' then (7 - ##datefirst + 4) % 7 + 1
when 'Fri' then (7 - ##datefirst + 5) % 7 + 1
when 'Sat' then (7 - ##datefirst + 6) % 7 + 1
end

Related

SQL - Group By Week to begin on a specific weekday without involving two transactions?

I am writing a query that returns the sum of rows for the last 10 weeks FRI-THURS.
It uses a group by to show the sum of each week:
WITH Vars (Friday) -- get current week Fridays Date
AS (
SELECT CAST(DATEADD(DAY,(13 - (##DATEFIRST + DATEPART(WEEKDAY,GETDATE())))%7,GETDATE()) AS DATE) As 'Friday'
)
SELECT datepart(week, DateField) AS WeekNum, COUNT(*) AS Counts
FROM Table
WHERE DateField >= DATEADD(week,-9, (SELECT Friday from Vars))
GROUP BY datepart(week, DateField)
ORDER BY WeekNum DESC
The problem is every week starts on Monday so the Group By doesn't group the dates on how I want it. I want a week to be defined as FRI-THURS.
One workaround to this is to use DATEFIRST. e.g:
SET DATEFIRST = 5; --set beginning of each week to Friday
WITH Vars (Friday) -- get current week Fridays Date
... rest of query
However due to limitations on the interface I am writing this query I cannot have two separate statements run. It needs to be one query with no semicolons.
How can I achieve this?
This should do it. First pre-compute once the StartingFriday of 9 weeks ago, rather than doing that for each row. Then compute the dfYear and dfWeek giving them alias-es, where their DateField is after the starting friday. Lastly, Count/GroupBy/OrderBy.
Declare #StartingFriday as date =
DATEADD(week,-9, (DATEADD(day, - ((Datepart(WEEKDAY,GETDATE()) +1) % 7) , GETDATE())) ) ;
SELECT dfYear, dfWeek, COUNT(*) AS Counts
FROM
(Select -- compute these here, and use alias in Select, GroupBy, OrderBy
(Datepart(Year,(DATEADD(day, - ((Datepart(WEEKDAY,DateField) +1) % 7) , DateField)) ) )as dfYear
,(Datepart(Week,(DATEADD(day, - ((Datepart(WEEKDAY,DateField) +1) % 7) , DateField)) ) )as dfWeek
From Table
WHERE #StartingFriday <= DateField
) as aa
group by dfYear, dfWeek
order by dfYear desc, dfWeek desc
-- we want the weeknum of the (Friday on or before the DateField)
-- the % (percent sign) is the math MODULO operator.
-- used to get back to the nearest Friday,
-- day= Fri Sat Sun Mon Tue Wed Thu
-- weekday= 6 7 1 2 3 4 5
-- plus 1 = 7 8 2 3 4 5 6
-- Modulo7= 0 1 2 3 4 5 6
-- which are the days to subtract from DateField
-- to get to its Friday start of its week.
I did some testing with this
declare #dt as date = '8/17/18';
select ((DATEPART(WEEKDAY,#dt) +1) % 7) as wd
,(DATEADD(day, - ((Datepart(WEEKDAY,#dt) +1) % 7) , #dt)) as Fri
,(Datepart(Week,(DATEADD(day, - ((Datepart(WEEKDAY,#dt) +1) % 7) , #dt)) ) )as wk
,DATEADD(week,-9, (DATEADD(day, - ((Datepart(WEEKDAY,#dt) +1) % 7) , #dt)) ) as StartingFriday

Getting an error Conversion failed when converting date and/or time from character string

The query shown below is causing an error
Conversion failed when converting date and/or time from character string
Please help me
SELECT
a.[Prod_id], a.[ctry_id], a.[ctry_cd],
left(a.[re_ver],8) + ' (Per ' + a.[re_ver] + ')' as [re_ver],
'YTD' as [per_type],
sum(b.[unt_cas_cy_bp]) [unt_cas_cy_bp],
sum(b.[unt_cas_cy_re]) [unt_cas_cy_re],
sum(b.[unt_cas_py_act]) [unt_cas_py_act],
sum(b.[unt_cas_2py_act]) [unt_cas_2py_act]
FROM
a
INNER JOIN
b ON a.Prod_id = b.Prod_id
AND a.ctry_id = b.ctry_id
AND a.ctry_cd = b.ctry_cd
AND b.per_type = 'Monthly'
AND YEAR(LEFT(b.re_ver, 8)) * 100 + MONTH(LEFT(b.re_ver, 8))
BETWEEN YEAR(LEFT(a.re_ver, 8)) * 100 + 1
AND YEAR(LEFT(a.re_ver, 8)) * 100 + MONTH(LEFT(a.re_ver, 8))
WHERE
a.per_type = 'Yearly'
GROUP BY
a.[Prod_id], a.[ctry_id], a.[ctry_cd],
a.[re_ver], a.[per_type]
The problem is your abbreviations can be 3 or 4 characters long. i.e. September is abbreviated Sept. You are trying to create a date column from this varchar field in an odd way, and it's not sargable. Instead, I would do the conversion in a CTE, and then use it in your where clause.
declare #badData table (re_ver varchar(64))
insert into #badData
values
('Feb 2017,Q4 2017'),
('Sept 2017,Q3 2016')
;with cte as(
select
re_ver
,re_ver_date = cast(
cast(case
when left(re_ver,4) = 'Jan' then 1
when left(re_ver,4) = 'Feb' then 2
when left(re_ver,4) = 'Mar' then 3
when left(re_ver,4) = 'Apr' then 4
when left(re_ver,4) = 'May' then 5
when left(re_ver,4) = 'Jun' then 6
when left(re_ver,4) = 'Jul' then 7
when left(re_ver,4) = 'Aug' then 8
when left(re_ver,4) = 'Sept' then 9
when left(re_ver,4) = 'Oct' then 10
when left(re_ver,4) = 'Nov' then 11
when left(re_ver,4) = 'Dec' then 12
end as varchar(2))
+ '/'
+ '01'
+ '/'
+ cast(right(substring(re_ver,1,charindex(',',re_ver) - 1),4) as char(4))
as date)
from
#badData)
select *
from cte
--where <your condition>
I'm getting the year from the 'Mon YYYY' part, not the Q# YYYY part in the query. However, if you want the year from the quarter part, just change the last line to:
cast(right(re_ver,4) as char(4))

How to handle DATEFIRST when using DATEPART

-- SET DATEFIRST to U.S. English default value of 7.
SET DATEFIRST 7;
SELECT
##DATEFIRST;
SELECT
GETDATE()
, DATEPART(dw , GETDATE()) AS DayOfWeek;
-- January 1, 1999 is a Friday. Because the U.S. English default
-- specifies Sunday as the first day of the week, DATEPART of 1999-1-1
-- (Friday) yields a value of 6, because Friday is the sixth day of the
-- week when you start with Sunday as day 1.
SET DATEFIRST 3;
SELECT
##DATEFIRST;
-- Because Wednesday is now considered the first day of the week,
-- DATEPART now shows that 1999-1-1 (a Friday) is the third day of the
-- week. The following DATEPART function should return a value of 3.
SELECT
GETDATE()
, DATEPART(dw , GETDATE()) AS DayOfWeek;
SET DATEFIRST 7;
How do we handle getting the DATEPART (1 = Sunday always) irregardless of DATEFIRST setting?
I really don't want to do a case and subtract...
this always seems ridiculous to me, how about
select datediff(day,0, getdate()) % 7
where 6 represents Sunday
or you could do
select (datediff(day,0, '2016-07-31') - 5) % 7
to get Sun = 1, Mon = 2, Tue = 3 ... etc
or you could do this fiddle
select (datepart(weekday,get_date()) + ##datefirst - 1) % 7 + 1
seems to work for all datepart
set datefirst 5
select (datepart(weekday,'2016-07-31') + ##datefirst - 1) % 7 + 1
select (datepart(weekday,'2016-08-01') + ##datefirst - 1) % 7 + 1
select (datepart(weekday,'2016-08-02') + ##datefirst - 1) % 7 + 1
select (datepart(weekday,'2016-08-03') + ##datefirst - 1) % 7 + 1
select (datepart(weekday,'2016-08-04') + ##datefirst - 1) % 7 + 1
select (datepart(weekday,'2016-08-05') + ##datefirst - 1) % 7 + 1
select (datepart(weekday,'2016-08-06') + ##datefirst - 1) % 7 + 1
select (datepart(weekday,'2016-08-07') + ##datefirst - 1) % 7 + 1
This code selects Monday as the first day of week whatever the setting in your engine:
((datepart(DW, #YourDateVariable) + ##DATEFIRST + 5) % 7) + 1
by adding ##DATEFIRST value before the modulus operator it neglects the datefirst setting in your SQL engine.
The value 5 is to make Monday as the first day of the week
To make Sunday as the first day of the week add 6
to make saturday as the first day of the week then add 0
and so on the rest of the day weeks.
Perhaps not the most elegant, but instead of doing the subtraction you can just set it to 7 and then back to what ever it was after your DATEPART
SET DATEFIRST 7;
SELECT DATEPART(dw , GETDATE()) --6
SET DATEFIRST 3;
DECLARE #currentDatefirst int = ##DATEFIRST
SELECT ##DATEFIRST --3
SET DATEFIRST 7;
SELECT DATEPART(dw , GETDATE()) --6
SET DATEFIRST #currentDatefirst
SELECT ##DATEFIRST --3

Add a number (13) to the month and change the day to the 1st of that month

I am sure this one is simple but I am having a difficult time figuring it out. I am trying to add 13 months to a date and that resulting month needs to default to the 1st day of the month.
Example:
Date: 1/25/2016
Query results: 2/1/2017
Here is the query I am using:
SELECT Dateadd(month,13,getdate())
This should work for you. Just replace GETDATE() with your date.
select dateadd(month, datediff(month, 0, dateadd(month, 13, GETDATE())), 0)
SQL 2012+
SELECT DATEADD(DAY, 1, EOMONTH(GETDATE(), 12))
You can just construct the date from the constituent parts, by adding 1 year + 1 month and forcing the day part to 1 (and taking care of the special case of month = 12), like this:
select DATEFROMPARTS (
year(getdate()) + case when month(getdate()) = 12 then 2 else 1 end,
case when month(getdate()) = 12 then 1 else month(getdate()) + 1 end,
1
)

SQL Adding integer strings with zero values

I am trying to add strings which are integers. I have 201404 as input and I need it to be converted to 201503 so the only way to do this is to increase the year (2014) by 1 and decrease the month 02 by 1.
I have tried the below but the leading zero in the month does not seem to preserve:
DECLARE #YearMonth INT = 201404
, #left INT = 0
, #right INT = 0
SET #YearMonth = CAST(#YearMonth AS VARCHAR(6))
SET #left = CAST(LEFT(#YearMonth, 4) + 1 AS VARCHAR(MAX))
SET #right = RIGHT(#YearMonth, 2) - 1
SET #right = CAST(#right AS VARCHAR(2))
SET #right = RIGHT(('0' + CAST(#right AS VARCHAR(2))), 2)
PRINT #left
PRINT RIGHT('0' + LTRIM(RTRIM(#right)), 6)
Dealing with integer YYYYMM format can be difficult when adding and subtracting months. One method is to convert to a number of months, and then convert back to the format. So, this converts the value to a number of months
select (#YearMonth / 100) * 12 + (#YearMonth % 100)
Then we can add a number, such as 11 and convert back to the integer format:
select (( (#YearMonth / 100) * 12 + (#YearMonth % 100) + 11) / 12) * 100 +
( (#YearMonth / 100) * 12 + (#YearMonth % 100) + 11) % 12)
) as yyyymm
Another method that might be simpler is to use date arithmetic:
select dateadd(11, month, cast(#YearMonth as varchar(255)) + '01')
This returns a date. You can convert it back to the number as:
select (year(dateadd(11, month, cast(#YearMonth as varchar(255)) + '01')) * 100 +
month(dateadd(11, month, cast(#YearMonth as varchar(255)) + '01'))
) as yyyymm
Use REPLICATE
replicate('0', 2 - len(#right)) + #right
Just ran this:
DECLARE #YearMonth INT = 201404;
SELECT CONVERT(VARCHAR(6), DATEPART(YEAR, T.Data) + 1) + RIGHT(100 + DATEPART(MONTH, T.Data) -1, 2)
FROM (VALUES (CONVERT(VARCHAR(8), #YearMonth) + '01')) AS T(Data);
Result:
201503
It's going to pick month number and add 100 to it and then pick 2 right chars from it, so for instance you got 4, it becomes 104 and then RIGHT function picks last 2 characters, which are 04.
Checked with other params, seems fine:
DECLARE #YearMonth INT = 201411;
SELECT CONVERT(VARCHAR(6), DATEPART(YEAR, T.Data) + 1) + RIGHT(100 + DATEPART(MONTH, T.Data) -1, 2)
FROM (VALUES (CONVERT(VARCHAR(8), #YearMonth) + '01')) AS T(Data);
Result:
201510
I would convert implicitly to date, add 11 months and then format back as a string. The integer conversion would be implicit as well.
select format(dateadd(month, 11, str(#YearMonth) + '01'), 'yyyyMM')

Resources