SQL converting month into Years and Months - sql-server

I have an X number of months, but I need to break it into xx years yy months in SQL.
For example: 31 months should be 2 years 7 months.
Is there any inbuilt function or something to help?
Many thanks for your help.

You can use modulus to get the months and floor to get the years
SELECT totalmonths, FLOOR(tottalmonths / 12) AS years, totalmonths % 12 as months
FROM -- ...

You can try this:
SELECT
(months_column_name / 12) AS years,
(months_column_name % 12) AS months
FROM table_name

You can create a solution the uses built-in functions, but I'd hardly call it helpful when olde fashioned arithmetic operators will provide the desired results in a much more concise manner, e.g. Hogan's answer. dbfiddle.
with
SomeMonths as (
-- Create some test data from 0 to 100.
select 0 as Months
union all
select Months + 1
from SomeMonths
where Months < 100 ),
CompleteDate as (
-- Convert the number of months into a date based at 1 January 1.
select Months, DateAdd( month, Months, Cast( '00010101' as Date ) ) as Sometime
from SomeMonths )
select Months,
-- Make the number of years zero-based.
Year( Sometime ) - 1 as TheYears,
-- Make the number of months zero-based.
Month( Sometime ) - 1 as TheMonths
from CompleteDate;

Hi there Unknown Coder,
I made some code here that will display the number of months and years..
It also has a more human friendly way of displaying the data, like in your example.
So that last one will display as "2 years 7 months" if your value was 31.
Here's my code with the temp database for testing:
Declare #monthtest TABLE
(
NumOfMonths int
);
INSERT INTO #monthtest (NumOfMonths) select 11
INSERT INTO #monthtest (NumOfMonths) select 13
INSERT INTO #monthtest (NumOfMonths) select 31
select
cast(x1.NumOfMonths / 12 as int) as years,
(x1.NumOfMonths ) % 12 as months,
concat(
cast(x1.NumOfMonths / 12 as int),
(case when cast(x1.NumOfMonths / 12 as int) = 1 then ' year ' else ' years ' end ),
(x1.NumOfMonths ) % 12,
(case when (x1.NumOfMonths ) % 12 = 1 then ' month' else ' months' end )
) as combined
from #monthtest as x1
This will output as
years
months
combined
0
11
0 years 11 months
1
1
1 year 1 month
2
7
2 years 7 months

Related

Retrieve data 14 days prior to their "date of manufacture" irrespective of Year in SQL Server

I need all the rows that are 14 days next to my current date and that should not depend upon the Year. For example if today is 2nd of September, then the query should return all the rows of which u_dateofmanufacture is (2+14) 16th September, no matter which year it belongs. the focus is only on the date and the month.
I have also attached the screenshot and the column "date of Manufacture" is highlighted.
According to the screenshot only the rows 2,3 and 4 should be returned. They all have different year but the day and month is same(09-16).
I am using SQL Server.
declare #date DATE = dateadd(d,14,getdate())
select * from your table where month(u_dateofmanufacture)= month(#date) and day(u_dateofmanufacture) = day(#date)
You have a problem with leap years and the first 14 days of the year. If we skip these problems, you can use:
where month(datecol + 14) * 100 + day(datecol + 14) >= month(getdate()) * 100 + day(getdate()) and
month(datecol) * 100 + day(datecol) < month(getdate()) * 100 + day(getdate())
I would use a join on a virtual table containing all the possible years
SELECT t.*
FROM YourTable t
JOIN (
SELECT
starting = DATEADD(day, -14, DATEFROMPARTS(v.year, MONTH(GETDATE(), DAY(GETDATE())),
ending = DATEFROMPARTS(v.year, MONTH(GETDATE(), DAY(GETDATE()))
FROM (VALUES
(2023),(2022),(2022),(2021),(2020),(2019),(2018),(2017),(2016),(2015),(2014),(2013),(2012),(2011)
) v(year)
) v ON t.u_dateofmanufacture >= v.starting
AND t.u_dateofmanufacture < v.ending
you can use a query like below
select * from yourtable
where month(u_dateofmanufacture)= month(dateadd(d,14,getdate()))
and day(u_dateofmanufacture) =day(dateadd(d,14,getdate()))
optimally
declare #seekdate = dateadd(d,14,getdate())
select * from yourtable
where month(u_dateofmanufacture)= month(#seekdate )
and day(u_dateofmanufacture) =day(#seekdate)

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

Calculate duration in years if months increases from 12 months

I have a column that accepts values in NoOfMonths which I want to calculate in years. My table structure let's say is given below
CREATE TABLE Duration
(
TotalMonths int
);
INSERT INTO Duration VALUES (24);
INSERT INTO Duration VALUES (18);
INSERT INTO Duration VALUES (7);
I want the result to be shown like this,
Months Duration
24 2 Years
18 1 Year 6 Months
7 7 Months
You can get the data like this
select duration,
duration / 12 as years,
duration % 12 as months
from your_table
You should do the rest in the presentation layer of your program.
Try This
SELECT
*,
CASE WHEN TotalMonths>12
THEN CAST(TotalMonths/12 AS VARCHAR(10))+' Years '
ELSE '' END
+
CASE WHEN TotalMonths%12>0
THEN CAST(TotalMonths%12 AS VARCHAR(10))+' Months'
ELSE '' END
FROM Duration
Something like this
DECLARE #Duration TABLE(TotalMonths int);
INSERT INTO #Duration VALUES (24),(18),(7);
SELECT d.TotalMonths
,A.*
, CASE WHEN A.CountYears>0 THEN CAST (A.CountYears AS VARCHAR(10)) + ' years ' ELSE '' END
+ CASE WHEN A.CountMonths>0 THEN CAST(A.CountMonths AS VARCHAR(10)) + ' months' ELSE '' END AS TextDescription
FROM #Duration AS d
CROSS APPLY(SELECT d.TotalMonths / 12 AS CountYears
,d.TotalMonths % 12 AS CountMonths) AS A;
Edited to using modulo operator %
The result
+-------------+------------+-------------+------------------+
| TotalMonths | CountYears | CountMonths | TextDescription |
+-------------+------------+-------------+------------------+
| 24 | 2 | 0 | 2 years |
+-------------+------------+-------------+------------------+
| 18 | 1 | 6 | 1 years 6 months |
+-------------+------------+-------------+------------------+
| 7 | 0 | 7 | 7 months |
+-------------+------------+-------------+------------------+
Hint: The integer division will silently round to integer values.
you can do that like this :
declare #Duration table (TotalMonths int)
INSERT INTO #Duration VALUES (24), (18), (7)
select d.TotalMonths as months,
case when d.TotalMonths / 12 > 0 then convert(varchar, d.TotalMonths / 12) + ' years ' else '' end
+
case when d.TotalMonths % 12 > 0 then convert(varchar, d.TotalMonths % 12) + ' Months' else '' end
as Duration
from #Duration d
the result is
months Duration
------ --------
24 2 years
18 1 years 6 Months
7 7 Months
You need to check how to display a dummy column, and do the math in it.
something like this
select TotalMonths, ((select TotalMonths from Duration) / 12) As DurationInYears from Duration
here is a simple way that you can convert an integer value into month and days:
SELECT Duration(dd,366,0)
this will convert duration value into months and years.

SQL Server : set weeknumber fiscal year

I have a stored procedure that creates a calendar table that spans many years for my financial reports, example the years run from 01/06/2015 to 31/05/2016. I want to change the weeknumber calculation so that it starts counting the weeks from the 01/06/2016
I found some code that I modified that nearly works but the first week on June is classed as 0 and not 1
DATEDIFF(week
,DATEADD(YEAR
,DATEDIFF(MONTH
,'19000601'
,#StartDate
) / 12
,'19000601'
)
,dateadd(d
,6 - datepart(w
,cast(year(#StartDate)
- case when month(#StartDate) < 6
then 1
else 0
end
as char(4)
)
+'0601'
)
,#StartDate
)
) AS WeekNum,
and
datediff(d
,cast(year(#StartDate) - case when month(#StartDate) < 6
then 1
else 0
end
as char(4)
)
+ '0601'
,#StartDate
) / 7 AS WeekNum,

Return number of months and years from int?

This seems pretty easy, but I can't seem to figure it out.
If i have a number of months, like 61
That is 5 years and 1 month.
How can I write a select to give me the value of 0105?
Presumably you're going to have a query like this:
SELECT MONTHS
FROM MY_TABLE;
You could do some division and get the number of years:
SELECT MONTHS / 12 AS YEARS
FROM MY_TABLE;
Next, you need to get the number of months remaining from that. Modulo mathematical operations are used for this:
SELECT MONTHS % 12 AS MONTHS,
MONTHS / 12 AS YEARS
FROM MY_TABLE;
Now you'll need to format it:
SELECT FORMAT(MONTHS % 12 AS MONTHS, '00'),
FORMAT(MONTHS / 12 AS YEARS, '00')
FROM MY_TABLE;
Finally, concat the two results together:
SELECT CONCAT(FORMAT(MONTHS % 12 AS MONTHS, '00'),
FORMAT(MONTHS / 12 AS YEARS, '00')) AS RESULT
FROM MY_TABLE;
you need some case , cast , /12 and %12:
declare #value int
set #value=61
select
case when len(cast(#value%12 as int))=1 then '0'+cast(#value%12 as varchar(1)) else cast(cast(#value%12 as int)as varchar(2)) end+
case when len(cast(#value/12 as int))=1 then '0'+cast(#value/12 as varchar(1)) else cast(cast(#value/12 as int)as varchar(2)) end
output: 0105
Here You have two possible solutions:
DECLARE #n INT = 61
SELECT RIGHT(REPLACE(CONVERT(varchar(8),DATEADD(Month,#n,'2000-01-01'),1),'/',''),4)
SELECT RIGHT(CAST(10000+#n%12*100+#n/12 AS VARCHAR(5)),4)

Resources