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')
Related
I have a column in a table that stores the number of minutes as a numeric(18,4) field named [course_access_minutes].
The stored values come from a blackboard database and look like this:
0.0500
0.0667
0.3667
up to
314.0833
625.8167
How do I convert these to time hh:mm, I've had a good look at the database documentation and all I can find is
course_access_minutes numeric(18,4) This is the number of minutes that the user accesses this course in total during this login session.
Can I assume that I can make a direct conversion from minutes into hours? I think I will take any values below 1 as 0 minutes. What is the best way to do this in SQL? Thanks in advance for your help.
Try this
SELECT CONVERT(varchar, DATEADD(s, 625.8167 * 60, 0), 108)
If the duration is longer than 24 hours you can use this
SELECT CONVERT(varchar, CAST(1877.4501 * 60 AS int) / 3600)
+ RIGHT(CONVERT(varchar, DATEADD(s, 1877.4501 * 60, 0), 108), 6)
You could use FLOOR like this
DECLARE #SampleData AS TABLE
(
Minutes numeric(18,4)
)
INSERT INTO #SampleData
VALUES
( 0.0500),
( 1.0500),
( 30.0500),
( 80.0500),
( 314.0833),
( 625.8167)
SELECT CONCAT(floor(sd.Minutes/60),':', CASE WHEN sd.Minutes - floor(sd.Minutes/60)*60 < 1 THEN '0'
ELSE FLOOR(sd.Minutes - floor(sd.Minutes/60)*60 )
END) AS hours
FROM #SampleData sd
Returns
hours
0:0
0:1
0:30
1:20
5:14
10:25
WITH _Samples AS (
SELECT CONVERT(numeric(18, 4), 0.0500) [course_access_minutes]
UNION ALL SELECT 0.0667
UNION ALL SELECT 0.3667
UNION ALL SELECT 314.0833
UNION ALL SELECT 625.8167
)
SELECT
S.course_access_minutes,
-- split out the number
FLOOR(S.course_access_minutes / 60) [hours],
FLOOR(S.course_access_minutes % 60) [minutes],
FLOOR((S.course_access_minutes - FLOOR(S.course_access_minutes)) * 60) [seconds],
-- to a string
CONVERT(varchar(10), FLOOR(S.course_access_minutes / 60))
+ ':' + RIGHT('00' + CONVERT(varchar(10), FLOOR(S.course_access_minutes % 60)), 2)
+ ':' + RIGHT('00' + CONVERT(varchar(10), FLOOR((S.course_access_minutes - FLOOR(S.course_access_minutes)) * 60)), 2) [time_string],
-- You could consider converting to the time data type if the values will never exceed the limit
-- time supports 00:00:00.0000000 through 23:59:59.9999999
-- 0 through 1439.9833333 ... 23 * 60 = 1380 + 59 = 1439 + (59 / 60) = 1439.9833333
-- (see: https://learn.microsoft.com/en-us/sql/t-sql/data-types/time-transact-sql)
CONVERT(time,
CONVERT(varchar(10), FLOOR(S.course_access_minutes / 60))
+ ':' + RIGHT('00' + CONVERT(varchar(10), FLOOR(S.course_access_minutes % 60)), 2)
+ ':' + RIGHT('00' + CONVERT(varchar(10), FLOOR((S.course_access_minutes - FLOOR(S.course_access_minutes)) * 60)), 2)
) [time]
FROM
_Samples S
(It wouldn't be difficult to further this idea and split out the fractional seconds as well.)
Which yields:
course_access_minutes hours minutes seconds time_string time
---------------------- ------ -------- -------- ------------ ----------------
0.0500 0 0 3 0:00:03 00:00:03.0000000
0.0667 0 0 4 0:00:04 00:00:04.0000000
0.3667 0 0 22 0:00:22 00:00:22.0000000
314.0833 5 14 4 5:14:04 05:14:04.0000000
625.8167 10 25 49 10:25:49 10:25:49.0000000
Note that this is going to be like Greg's answer, but I wanted to explain and simplify it.
You have minutes, so dividing them by 60 and flooring it (removing the decimal) gives the hours (without the minutes).
If you take the total minutes again, and remove (mod it by) the floored hours - which requires conversion to minutes by multiplying by 60 - you are left with the remaining minutes by essentially just finding out what is left after taking away that many groups of sixties:
SELECT FLOOR(course_access_minutes / 60) as Hours,
(FLOOR(course_access_minutes) % 60) as Minutes
FROM MyTable
If you want the decimal to appear for the amount of minute fractions (you want the seconds to appear, in decimal form), remove FLOOR.
If you want seconds in real numbers, keep FLOOR and use what Greg had: FLOOR((S.course_access_minutes - FLOOR(S.course_access_minutes)) * 60) for seconds. Be careful with the parenthesis, though, because you can end up accidentally flooring your decimaled minutes and get 0, and then 0*60 is zero:
FLOOR(
(
course_access_minutes -
FLOOR(course_access_minutes)
) * 60
) as Seconds
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
In a table, I have a column (AvgWaitTime) which stores data value in seconds (Data Type: float), date wise. I have a function which performs some calculation using AvgWaitTime column and other few columns and returns a value in time format. I would to convert the value returned by the function (time format) into seconds (preferrably decimal, if not then int).
select
(datepart(HH, dbo.fnGetMonthlyAverageWaitTime(m.RDate) * 60 * 60) +
datepart(mi, dbo.fnGetMonthlyAverageWaitTime(m.RDate) * 60) +
datepart(s, dbo.fnGetMonthlyAverageWaitTime(m.RDate)))[MonthlyAverageWaitTime]
from TelephonyMTD m
Error: Operand type clash: time is incompatible with int
So, I tried to run this:
select
(datepart(HH, GetDate() * 60 * 60) +
datepart(mi, GetDate() * 60) +
datepart(s, GetDate()))
Now it says, Implicit conversion from data type datetime to int is not allowed. Use the CONVERT function to run this query. Which is true when I looked at the data type conversion chart, I came to know that conversion to int and float is now allowed.
Please advice.
The problem is you are trying to multiply a date/datetime by an integer which doesn't make sense:
GetDate() * 60 * 60
You could simply use DATEDIFF with seconds, to get the value in seconds:
SELECT DATEDIFF(SECOND, '00:00:00', dbo.fnGetMonthlyAverageWaitTime(m.RDate)) AS MonthlyAverageWaitTime
FROM TelephonyMTD AS m
QUICK EXAMPLE
SELECT t.AvgTime,
AvgTimeInSeconds = DATEDIFF(SECOND, '00:00:00', t.AvgTime)
FROM (VALUES
(CAST('00:01:15' AS TIME)),
(CAST('05:36:47' AS TIME))
) AS t (AvgTime);
Which gives:
+----------+------------------+
| AvgTime | AvgTimeInSeconds |
+----------+------------------+
| 00:01:15 | 75 |
| 05:36:47 | 20207 |
+----------+------------------+
Open and Close brackets are the one causing issue for the above error: Please try like below
SELECT (
( Datepart(HH, Getdate()) * 60 * 60 ) +
( Datepart(mi, Getdate()) * 60 ) +
Datepart(s, Getdate())
)
Try to use Below Syntax to convert seconds to day, hour, minute, seconds
DECLARE #sec INT = 86400;
SELECT
CAST(#sec /60/60/24 AS VARCHAR(12)) + ' Days,'
+ CAST(#sec /60/60 % 24 AS VARCHAR(12))+ ' Hours,'
+ CAST(#sec /60 % 60 AS VARCHAR(2)) + ' Minutes, '
+ CAST(#sec % 60 AS VARCHAR(2)) + ' Seconds.';
I would like to get the average of each user_id for a specific time period.
Since RIGHT works on strings , I have to convert it to int and get the average.
For that reason I get error:
Conversion failed when converting the varchar value '08:36' to data
type int.
SELECT
user_id,
avg(convert (int , right('0' + convert(VARCHAR(2),datediff (second, QueueEndDt,ConnClearDt)/ 60 % 60), 2) + ':' +
right('0' + convert(VARCHAR(2),datediff (second, QueueEndDt,ConnClearDt)% 60),2))) as average_minutes
FROM Detail
WHERE QueueEndDt between '2015-02-09 08:00:00.000' AND '2015-02-09 23:02:33.043'
group by user_id
Without using the average and convert I get the correct datediff.
I made a http://sqlfiddle.com/#!6/298eb with some data.
What I would like to output is average of each user_id.
This will return you the average difference in hh:mm:ss format. Note that hh may exceed to 24. Modify the query to add years, months and days part.
WITH CTE AS(
SELECT
user_id,
Average_Seconds = AVG(DATEDIFF(SECOND, QueueEndDt, ConnClearDt))
FROM details
WHERE
QueueEndDt BETWEEN '2015-02-09 08:00:00.000' AND '2015-02-09 23:02:33.043'
GROUP BY user_id
)
SELECT
user_id,
[Average hh:mm:ss] =
CONVERT(VARCHAR(12), Average_Seconds / 60 / 60) + ':'
+ RIGHT('00' + CONVERT(VARCHAR(2), Average_Seconds / 60 % 60), 2) + ':'
+ RIGHT('00' + CONVERT(VARCHAR(2), Average_Seconds % 60), 2)
FROM CTE
RESULT
user_id Average hh:mm:ss
---------- ------------------
number1 13:44:16
number2 13:50:36
number3 13:46:33
This is the format I need from a T-SQL Column HH:MM:SS
Example:
SELECT CONVERT(varchar,GETDATE(),108) -- 11:06:03
I have these values: (Select duration from MyTable)
2:13:00
11:02
0:43
That needs to be this:
02:13:00
00:11:02
00:00:43
How can this be done in T-SQL?
Use Convert, then cast
transformation. The peculiarity here is hidden in omitted hours string, while sql server assumes seconds omitted.
Select
CONVERT(time(0),
case when len(duration) > 5 then duration else '00:' + duration end, 108)
from MyTable
Examples:
SELECT CONVERT(time(0),
case when len('2:13:00') > 5 then '2:13:00' else '00:' + '2:13:00' end ,108)
SELECT CONVERT(time(0),
case when len('11:02') > 5 then '11:02' else '00:' + '11:02' end ,108)
SELECT CONVERT(time(0),
case when len('0:43') > 5 then '0:43' else '00:' + '0:43' end ,108)
--------------
02:13:00
00:11:02
00:00:43
Update1: optimized the answer to time(0) due #Mikael Eriksson tip
Update2: modified solution concerning example2 requirement
This did it for me at the end.....
SELECT RIGHT('000' + CASE WHEN LEN(Duration) > 5
THEN LEFT(duration, CHARINDEX(':', duration) - 1)
ELSE 0 -- Hours
END, 3) + ':' +
RIGHT('00' + CASE WHEN LEN(Duration) > 5
THEN SUBSTRING(duration
,CHARINDEX(':',duration) + 1
,CHARINDEX(':',duration
,CHARINDEX(':',duration) + 1) - 1- CHARINDEX(':',duration))
ELSE LEFT(duration,CHARINDEX(':',duration) - 1)END, 2) + ':' + -- Minutes
RIGHT('00'+ RIGHT(duration, 2), 2) -- Seconds
NewDuration
FROM MyTable