Show dates against each un-pivoted column? - sql

I have written this query to convert columns into the rows.
select [ProjectName], EachDay, Hours
from [dbo].[TimeSheet_Child]
unpivot
(
Hours
for EachDay in ([Mon], [Tue], [Wed])
) u
but instead of EachDay I need dates that comes between the start and end of the week e.g.
Currently:
ProjectName EachDay Hours
A Mon 2
B Tue 8
C Wed 1
Should be
ProjectName EachDay Hours
A 15Dec2019 2
B 16Dec2019 8
C 17Dec2019 1
To pick dates between week start and end I have written this.
Declare #Year int
,#Week int
,#YearText varchar(4)
set #Year = 2019
set #Week = 51
set #YearText = #Year
Declare #Increment int
Set #Increment= 1
declare #date datetime
Set #date= dateadd(day
,#Increment - datepart(dw, #YearText + '-01-01')
+ (#Week-1) * 7
,#YearText + '-01-01')
print #date
While (#Increment < 8)
Begin
print dateadd(day
,#Increment - datepart(dw, #YearText + '-01-01')
+ (#Week-1) * 7
,#YearText + '-01-01')
Set #Increment= #Increment + 1
End

Related

How Calculate Expire Date in SQL Query

I have this query for expiry date calculation and its work fine but result show in - eg:-9 year 4 month and 5 day.
I want to show that in normal way like "Expire in 9 years 4 months and 5 day":
DECLARE #TempDate Datetime ,
#ExpiryDate Datetime,
#year int,
#month int,
#day int
SET #ExpiryDate = (SELECT TOP (1) [ExpiryDate] FROM [dbo].[Purchases] WHERE [ProductId] = 1)
SELECT #TempDate = #ExpiryDate
SELECT
#year = DATEDIFF(YEAR, #TempDate, GETDATE()) -
CASE
WHEN (MONTH(#ExpiryDate) > MONTH(GETDATE())) OR
(MONTH(#ExpiryDate) = MONTH(GETDATE()) AND DAY(#ExpiryDate) > DAY(GETDATE()))
THEN 1 ELSE 0
END
SELECT #TempDate = DATEADD(YEAR, #year, #TempDate)
SELECT #month = DATEDIFF(MONTH, #TempDate, GETDATE()) -
CASE
WHEN DAY(#ExpiryDate) > DAY(GETDATE())
THEN 1 ELSE 0
END
SELECT #TempDate = DATEADD(MONTH, #month, #TempDate)
SELECT #day = DATEDIFF(DAY, #TempDate, GETDATE())
SELECT #year AS Years, #month AS Months, #day AS [Days]
If I understand your question correctly, the calculation is working as you expect but you want the Years value to be returned as a positive rather than negative number. If this is the case, you should change the final SELECT to:
SELECT (#year * -1) AS Years, #month AS Months, #day AS [Days];
Alternatively if you want to return the output as a string (i.e. Expire in 9 years 4 months and 5 day), change the final SELECT to:
SELECT 'Expire in ' + CAST((#year * -1) AS VARCHAR(2)) + ' years '
+ CAST(#month AS VARCHAR(2)) + ' months and '
+ CAST(#day AS VARCHAR(2)) + ' day';
Casting as VARCHAR(2) assumes that you expect no more than 99 years, but you may want to increase that number.

Find Quarter Months Based on Payroll Cycle

This would be in the "where" clause...how do I find quarters based on a payroll cycle? Our payroll cycle starts on the 25th of the quarter month and ends on the 10th of the quarter month. For example...
The 2nd quarter starts on 4/25/2016 and ends on 7/10/2016.
Ok it's kind of hard to understand completely what you are doing but here is something that should work. You can edit the dates to fit what you want but I made it based off what you stated.
--This is just test data... you can use your own table
IF OBJECT_ID('tempdb..#payroll') IS NOT NULL DROP TABLE #payroll
CREATE TABLE #payroll (dates date)
INSERT INTO #payroll (dates) VALUES
('1/1/2016'),
('1/16/2016'),
('2/4/2016'),
('3/3/2016'),
('3/19/2016'),
('4/18/2016'),
('5/6/2016'),
('6/4/2016'),
('6/29/2016'),
('7/4/2016'),
('7/31/2016'),
('8/9/2016'),
('9/1/2016'),
('10/3/2016'),
('10/19/0216'),
('11/4/2016'),
('11/21/2016'),
('12/2/2016'),
('1/1/2016'),
('1/8/2017'),
('1/21/2017')
--variable for what ever quarter you want to limit on. 1-4
declare #Quarter int
set #Quarter = 4
--Year that you are focused on. If left to NULL it uses the current year
declare #Year int
set #Year = NULL
IF #Year IS NULL
BEGIN
SET #Year = Year(GETDATE())
END
--Date parameters that we will use to filter
declare #startDate date = null
declare #endDate date = null
--logic to set your quarters
set #startDate = case
when #Quarter = 1 then '1/25/' + CAST(#Year as varchar(4))
when #Quarter = 2 then '4/25/' + CAST(#Year as varchar(4))
when #Quarter = 3 then '7/25/' + CAST(#Year as varchar(4))
when #Quarter = 4 then '9/25/' + CAST(#Year as varchar(4))
end
set #endDate = case
when #Quarter = 1 then '4/10/' + CAST(#Year as varchar(4))
when #Quarter = 2 then '7/10/' + CAST(#Year as varchar(4))
when #Quarter = 3 then '9/10/' + CAST(#Year as varchar(4))
when #Quarter = 4 then '1/10/' + CAST((#Year + 1)as varchar(4))
end
--run it to test results
select *
from #payroll
where dates between #startDate and #endDate

adding 7 days to a date until end of month sql server

I want to find the first day of the month add 7 days and keep on adding 7 days not going over available days left in that month.
Example
July 1 – 7 --> 7 Days
July 8 – 14 --> 7 Days
July 15 – 21 --> 7 Days
July 22 – 28 --> 7 Days
July 29 - 31 --> 3 Days`
This works for me. Could be generalized to not have to start on the first day of the month and there is probably a more compact way to do this, but this gets the job done.
declare #month varchar(2) = '10',
#year varchar(4) = '2015',
#fullWeekCount int;
declare #firstOfTheMonth datetime = #year + '-' + #month + '-1';
declare #daysInMonth int = datediff(day, #firstOfTheMonth, dateadd(month, 1, #firstOfTheMonth))
select #fullWeekCount = (#daysInMonth / 6)
declare #i int = 1,
#startDate datetime = #firstOfTheMonth,
#endDate datetime;
declare #dates table (StartDay datetime, EndDay datetime);
while (#i <= #fullWeekCount)
begin
if (#i = #fullWeekCount)
set #endDate = #year + '-' + #month + '-' + cast(#daysInMonth as varchar(2));
else
set #endDate = dateadd(day, 6, #startDate)
insert into #dates (StartDay, EndDay)
values (#startDate, #endDate)
set #startDate = dateadd(day, 1, #endDate)
set #i = #i + 1;
end
select * from #dates d

Finding Closest future date

Is it possible to find the closest future date (datetime) by a date varchar value?
Given,
DECLARE #DayValue VARCHAR(3)
, #DateValue DATETIME
SET #DayValue = 'Tue' -- Values could be 'Mon', 'Tue', 'Wed' and etc.
SET #DateValue = '10/15/2014' -- Format is MM/dd/yyyy
I want to get:
Oct 21 2014 12:00AM
Using Loop,
DECLARE #DayValue VARCHAR(3)
,#DateValue DATETIME
SET #DayValue = 'tue'
SET #DateValue = '10/15/2014'
declare #i int= 1 ,#day varchar(3) = null
while (#i<=7 )
begin
Select #day = left(datename (dw,#DateValue),3)
if #day = #DayValue
begin
Select #DateValue
break
end
Select #DateValue = #DateValue+ 1
Select #i = #i+1
end
You could use this function if you had a date-table:
CREATE FUNCTION [dbo].[GetNextDayOfWeek]
( #DayOfWeek VARCHAR(3),
#DateValue datetime
)
RETURNS SmallDateTime
AS
BEGIN
DECLARE #NextDayOfWeek smalldatetime
SET #NextDayOfWeek = (
SELECT
MIN(d.Date)
FROM
tDefDate d
WHERE
d.Date > #DateValue
AND LEFT(DATENAME(Weekday, d.Date), 3) = #DayOfWeek);
RETURN #NextDayOfWeek
END
Then it's simple as:
select [dbo].[GetNextDayOfWeek]('Tue', Getdate()) -- next tuesday=> 2014-10-21
Note that it takes the language of the database into account. So if it's in german:
select [dbo].[GetNextDayOfWeek]('Die', Getdate()) -- next tuesday(Dienstag)
Here's a version that works also without a date-table (but is less efficient).
CREATE FUNCTION [dbo].[GetNextDayOfWeek]
( #DayOfWeek VARCHAR(3),
#DateValue datetime
)
RETURNS SmallDateTime
AS
BEGIN
DECLARE #NextDayOfWeek smalldatetime
;WITH CTE as
(
SELECT GetDate() DateValue, DayNum=0
UNION ALL
SELECT DateValue + 1, DayNum=DayNum+1
FROM CTE
WHERE DayNum <=7
)
SELECT #NextDayOfWeek = (
SELECT
MIN(d.DateValue)
FROM
CTE d
WHERE d.DateValue > #DateValue
AND LEFT(DATENAME(Weekday, d.DateValue), 3) = #DayOfWeek
)OPTION (MAXRECURSION 8);
RETURN #NextDayOfWeek
END
If you could define DayValue as an integer, you solve this problem with more elegant way:
DECLARE #DayValue int, #DateValue DATETIME 
SET #DayValue = 3 -- Values could be 1-Sun, 2-Mon, 3-Tue, 4-Wed and etc. 
SET #DateValue = '10/15/2014' -- Format is MM/dd/yyyy
select dateadd(day,(7 + #DayValue - datepart(w,#DateValue)), #DateValue)
TRY SQL FIDDLE DEMO
No loops and will work in selects with multiple rows. :)
DECLARE #DayValue CHAR(3)
DECLARE #DateValue DATETIME
DECLARE #FutureDate DATE
SET #DayValue='MON'
SET #DateValue='10/12/2014'
DECLARE #Days TABLE
(
[DayOfWeek] TINYINT,
[DayValue] CHAR(3)
)
INSERT INTO #Days([DayOfWeek],[DayValue])
SELECT 0,'SUN' UNION
SELECT 1,'MON' UNION
SELECT 2,'TUE' UNION
SELECT 3,'WED' UNION
SELECT 4,'THU' UNION
SELECT 5,'FRI' UNION
SELECT 6,'SAT'
SET #FutureDate=
DATEADD(DAY,
--Skip to next week if we are already on the desired day or past it
+ CASE WHEN ((SELECT [DayOfWeek] FROM #Days WHERE [DayValue]=#DayValue)<DATEPART(WEEKDAY,#DateValue)) THEN 7 ELSE 0 END
--reset to start of week (add one as DATEPART is base 1, not base 0)
- DATEPART(WEEKDAY,#DateValue) + 1
--Add the desired day of the week
+ (SELECT [DayOfWeek] FROM #Days WHERE [DayValue]=#DayValue)
,#DateValue)
SELECT #FutureDate
This is a bit chunky solution, but it works. :)
SET DATEFIRST 1
DECLARE #DateValue DateTime
, #DayValue VARCHAR(3)
, #tmp INT
SET #DateValue = '09/30/2014'
SET #DayValue = 'wed'
SET #tmp = CASE #DayValue
WHEN 'Mon' THEN (1 - DATEPART(dw, #DateValue) + 7) % 7
WHEN 'Tue' THEN (2 - DATEPART(dw, #DateValue) + 7) % 7
WHEN 'Wed' THEN (3 - DATEPART(dw, #DateValue) + 7) % 7
WHEN 'Thu' THEN (4 - DATEPART(dw, #DateValue) + 7) % 7
WHEN 'Fri' THEN (5 - DATEPART(dw, #DateValue) + 7) % 7
WHEN 'Sat' THEN (6 - DATEPART(dw, #DateValue) + 7) % 7
WHEN 'Sun' THEN (7 - DATEPART(dw, #DateValue) + 7) % 7
END
SELECT
CASE
WHEN #tmp = 0 THEN DATEADD (DAY, 7, #DateValue)
ELSE DATEADD (DAY, #tmp, #DateValue)
END

Get day of the week in month (2nd Tuesday, etc.)

I need an algorithm for calculating the number of the day of the week in the month. Like 1st Friday of the month, 3rd Monday of the month, etc.)
Any ideas are appreciated.
Here is the final result:
declare #dt date = GetDate()
declare #DayOfWeek tinyint = datepart(weekday,#dt)
declare #DayOfMonth smallint = day(#dt)
declare #FirstDayOfMonth date = dateadd(month,datediff(month,0,#dt),0)
declare #DayOfWeekInMonth tinyint = #DayOfMonth / 7 + 1 -
(case when day(#FirstDayOfMonth) > day(#dt) then 1 else 0 end)
declare #Suffix varchar(2) =
case
when #DayOfWeekInMonth = 1 then 'st'
when #DayOfWeekInMonth = 2 then 'nd'
when #DayOfWeekInMonth = 3 then 'rd'
when #DayOfWeekInMonth > 3 then 'th'
end
select
cast(#DayOfWeekInMonth as varchar(2))
+ #Suffix
+ ' '
+ datename(weekday,#Dt)
+ ' of '
+ datename(month,#dt)
+ ', '
+ datename(year,#Dt)
PS: And if you can think of a better way to state the problem, please do.
Followint code will give you 1st Wednesday of April 2014 for today:
SELECT cast((DATEPART(d, GETDATE() - 1) / 7) + 1 as varchar(12))
+ 'st ' + DATENAME(WEEKDAY, getdate()) + ' of ' +
DATENAME(month, getdate()) + ' ' + DATENAME(year, getdate());
For any date use the code below. It gives 5th Tuesday of April 2014 for #mydate = '2014-04-29' in the example:
DECLARE #mydate DATETIME;
SET #mydate = '2014-04-29';
SELECT
case
when DATEPART(d, #mydate) = 1 then cast((DATEPART(d, #mydate ) / 7) + 1 as varchar(12))
else cast((DATEPART(d, #mydate - 1) / 7) + 1 as varchar(12))
end
+
case
when (DATEPART(d, #mydate - 1) / 7) + 1 = 1 then 'st '
when (DATEPART(d, #mydate - 1) / 7) + 1 = 2 then 'nd '
when (DATEPART(d, #mydate - 1) / 7) + 1 = 3 then 'rd '
else 'th '
end
+ DATENAME(WEEKDAY, #mydate) + ' of ' +
DATENAME(month, #mydate) + ' ' + DATENAME(year, #mydate) as [Long Date Name]
Okeeeey my tuuuurn ,
Please rate my answer Metaphor hhh, Here's the cooode :
declare #v_month nvarchar(2) = '04'
,#v_annee nvarchar(4) = '2014'
declare #v_date date = convert(date,#v_annee+'-'+#v_month+'-01')
declare #v_date_2 date = dateadd(M,1,#v_date)
if OBJECT_ID('temp') is not null
drop table temp
create table temp(_date date, _DayOfMonth nvarchar(20), _order int)
while (#v_date<#v_date_2)
begin
set #v_date =#v_date;
WITH _DayOfWeek AS (
SELECT 1 id, 'monday' Name UNION ALL
SELECT 2 id, 'tuesday' Name UNION ALL
SELECT 3 id, 'wednesday' Name UNION ALL
SELECT 4 id, 'thursday' Name UNION ALL
SELECT 5 id, 'friday' Name UNION ALL
SELECT 6 id, 'saturday' Name UNION ALL
SELECT 7 id, 'sunday' Name)
insert into temp(_date,_DayOfMonth)
SELECT
#v_date
,(select Name from _DayOfWeek where id = DATEPART(WEEKDAY,#v_date))
SET #v_date = DATEADD(DAY,1,#v_date)
END
UPDATE tmp1
SET _order = _order_2
FROM temp tmp1
INNER JOIN
(SELECT *, ROW_NUMBER() OVER(PARTITION BY _DayOfMonth ORDER BY _date ASC) AS _order_2 FROM temp) tmp2
ON tmp1._date = tmp2._date
SELECT * FROM temp
SELECT *
FROM temp
WHERE _DayOfMonth = 'thursday'
AND _order = 3
I hope this will help you :)
Good Luck
OK, here's what I came up with, I'll +1 everyone who answered anyway:
declare #dt date = GetDate()
declare #DayOfWeek tinyint = datepart(weekday,#dt)
declare #DayOfMonth smallint = day(#dt)
declare #FirstDayOfMonth date = dateadd(month,datediff(month,0,#dt),0)
declare #DayOfWeekInMonth tinyint =
#DayOfMonth / 7 + 1
- (case when day(#FirstDayOfMonth) > day(#dt) then 1 else 0 end)
declare #Suffix varchar(2) =
case
when #DayOfWeekInMonth = 1 then 'st'
when #DayOfWeekInMonth = 2 then 'nd'
when #DayOfWeekInMonth = 3 then 'rd'
when #DayOfWeekInMonth > 3 then 'th'
end
select
cast(#DayOfWeekInMonth as varchar(2))
+ #Suffix
+ ' '
+ datename(weekday,#Dt)
+ ' of '
+ datename(month,#dt)
+ ', '
+ datename(year,#Dt)
declare #dt date = getdate()
declare #DayOfMonth smallint = datepart(d, #dt)
declare #Suffix varchar(2) =
case
when floor((#DayOfMonth - 1) / 7.0) = 0 then 'st' -- implies there were no such days previously in the month
when floor((#DayOfMonth - 1) / 7.0) = 1 then 'nd'
when floor((#DayOfMonth - 1) / 7.0) = 2 then 'rd'
else 'th'
end
select cast(floor((#DayOfMonth - 1) / 7.0) + 1 as varchar(1)) + #Suffix +
' ' + datename(weekday, #dt) + ' of ' + datename(month, #dt) +
', ' + datename(year, #dt)
DECLARE #dt DATETIME
SET #dt = DATEADD(d, 6, GETDATE())
SELECT #dt,
CAST((DAY(#dt) / 7) + CASE WHEN DATEPART(weekday, #dt) >= DATEPART(weekday, CAST(MONTH(#dt) AS NVARCHAR) + '/01/' + CAST(YEAR(#dt) AS NVARCHAR)) THEN 1 ELSE 0 END AS NVARCHAR)
+ '' + CASE (DAY(#dt) / 7) + CASE WHEN DATEPART(weekday, #dt) >= DATEPART(weekday, CAST(MONTH(#dt) AS NVARCHAR) + '/01/' + CAST(YEAR(#dt) AS NVARCHAR)) THEN 1 ELSE 0 END
WHEN 1 THEN N'st'
WHEN 2 THEN N'nd'
WHEN 3 THEN N'rd'
ELSE N'th'
END
+ ' ' + DATENAME(dw, #dt)
+ ' of ' + DATENAME(M, #dt)
+ ', ' + CAST(YEAR(#dt) AS NVARCHAR)
Result is a single SELECT (provided the assignment of #dt happened earlier) but is, essentially, the same logic as yours.
This following code will give you DATE for any day of the week in any month or year that you specify. All the variables that I have are to reduce repeating logic to improve code speed.
This code gives you date for 1st Monday in February in 2013
DECLARE #DayNumber INT = 1
,#DayWeekNumber INT = 2
,#MonthNumber INT = 2
,#YearNumber INT = 2013
,#FoM DATE
,#FoMWD INT;
SET #FoM = DATEFROMPARTS(#YearNumber,#MonthNumber,1)
SET #fomwd = DATEPART(WEEKDAY, #FoM);
SELECT CASE WHEN #fomwd = #DayWeekNumber THEN DATEADD(WEEK, #DayNumber - 1, #FoM)
WHEN #fomwd < #DayWeekNumber THEN DATEADD(DAY, #DayWeekNumber - #fomwd, DATEADD(WEEK, #DayNumber - 1, #FoM))
WHEN #fomwd > #DayWeekNumber THEN DATEADD(DAY, #DayWeekNumber - #fomwd, DATEADD(WEEK, #DayNumber, #FoM))
END AS DateOfDay;