How to Combine dates and time in separate fields in SQL - sql

Table :
schedule_id job_id next_run_date next_run_time
------------------------------------------------------
221 D23EA7B2 20151005 90000
222 18EDFB21 20151020 90000
242 90283725 20151001 170000
239 4B69C670 20151011 90000
Result :
schedule_id job_id next_run_date_Time
--------------------------------------------
221 D23EA7B2 2015-10-05 09:00 AM
222 18EDFB21 2015-10-20 09:00 AM
242 90283725 2015-10-01 05:00 PM
239 4B69C670 2015-10-11 09:00 AM
How to join next_run_date and next_run_time together as a single column?
My Query used in SSRS 2008
SELECT c.Name AS ReportName,[LastRunTime],
'Next Run Date' = CASE next_run_date WHEN 0 THEN null ELSE
substring(convert(varchar(15),next_run_date),1,4) + '/' +
substring(convert(varchar(15),next_run_date),5,2) + '/' +
substring(convert(varchar(15),next_run_date),7,2)
END,
--Need to add next_run_date_Time here
FROM
dbo.[Catalog] c
INNER JOIN dbo.[Subscriptions] S ON c.ItemID = S.Report_OID
INNER JOIN dbo.ReportSchedule R ON S.SubscriptionID = R.SubscriptionID
INNER JOIN msdb.dbo.sysjobs J ON Convert(nvarchar(128),R.ScheduleID) = J.name
INNER JOIN msdb.dbo.sysjobschedules JS ON J.job_id = JS.job_id
ORDER BY S.LastRunTime DESC

Assuming both are varchar, try this:
SELECT schedule_id, job_id,
CONVERT(datetime, next_run_date, 112)
+ CONVERT(time,
SUBSTRING(next_run_time, 1, LEN(next_run_time) - 4) + ':'
+ LEFT(RIGHT(next_run_time, 4), 2) + ':'
+ RIGHT(next_run_time, 2),
114) AS next_run_date_Time
FROM my_table
Here is a fiddle
If those fields are numbers, you can convert them in a sub-query first and then apply the same query above:
SELECT schedule_id, job_id,
CONVERT(datetime, next_run_date, 112)
+ CONVERT(time,
SUBSTRING(next_run_time, 1, LEN(next_run_time) - 4) + ':'
+ LEFT(RIGHT(next_run_time, 4), 2) + ':'
+ RIGHT(next_run_time, 2),
114) AS next_run_date_Time
FROM (SELECT schedule_id, job_id
, CAST(next_run_date AS VARCHAR(8)) AS next_run_date
, CAST(next_run_time AS VARCHAR(6)) AS next_run_time
FROM my_table) AS t
Here is a fiddle
EDIT you can update your query to use this concept like this:
SELECT c.Name AS ReportName,[LastRunTime],
CONVERT(datetime, next_run_date, 112)
+ CONVERT(time,
SUBSTRING(next_run_time, 1, LEN(next_run_time) - 4) + ':'
+ LEFT(RIGHT(next_run_time, 4), 2) + ':'
+ RIGHT(next_run_time, 2),
114) AS 'Next Run Date'
FROM
dbo.[Catalog] c
INNER JOIN dbo.[Subscriptions] S ON c.ItemID = S.Report_OID
INNER JOIN dbo.ReportSchedule R ON S.SubscriptionID = R.SubscriptionID
INNER JOIN msdb.dbo.sysjobs J ON Convert(nvarchar(128),R.ScheduleID) = J.name
INNER JOIN (SELECT schedule_id, job_id
, CAST(next_run_date AS VARCHAR(8)) AS next_run_date
, CAST(next_run_time AS VARCHAR(6)) AS next_run_time
FROM msdb.dbo.sysjobschedules) AS JS ON J.job_id = JS.job_id
ORDER BY S.LastRunTime DESC

Here is one way to do it:
-- Create sample table and data
CREATE TABLE tbl (
next_run_date char(8),
next_run_time varchar(6)
)
INSERT INTO tbl VALUES
(20151005, 93020),
(20151001, 170000)
using cte1 to pad next_run_time with a leading zero if needed,
and using cte2 to break the string to a "normal" time representation:
;with cte1 as
(
select next_run_date,
right('000000'+ next_run_time, 6) as run_time_base
FROM tbl
), cte2 as
(
select next_run_date,
left(run_time_base, 2) + ':' +
substring(run_time_base, 3, 2) + ':' +
right(run_time_base, 2) as run_time
from cte1
)
select cast(next_run_date as datetime) + cast(run_time as datetime) as run_datetime
from cte2
-- clean up
drop table tbl
Results:
run_datetime
-----------------------
2015-10-05 09:30:20.000
2015-10-01 17:00:00.000

I am assuming here that next_run_date & next_run_time, I have written query here which will give your desired output..
select
schedule_id
,job_id
,convert(datetime,
convert(varchar, convert(datetime, next_run_date, 112), 111)
+ ' ' + substring(REPLICATE('0',6-LEN(next_run_time)) + next_run_time, 1, 2)
+ ':' + substring(REPLICATE('0',6-LEN(next_run_time)) + next_run_time, 3, 2)
+ ':' + substring(REPLICATE('0',6-LEN(next_run_time)) + next_run_time, 5, 2)
) as next_run_date_Time
from TableName
Here is the sql fiddle

I think the simplest option, assuming both are varchars to begin with, is:
dateadd(HH, cast(left(time, len(time) - 4) as int), cast(date as datetime))
Convert the varchar date to a datetime format, which will default to midnight on the date, then add the number of hours specified by the time. The syntax above assumes times are always on the hour - if not, add minutes as necessary.
Once in datetime, you can use convert to specify any display format you like.

Related

Get OrderTotal by hourly for current date gives subquery error :

Here is my SQL query which presently gives hourly order data for current the date. Here I need to count order by following case when condition, if I add this I am getting sub-query error after 11:00 AM, Please anybody help me out to solve problem.
Following SQL query on which I am performing:
DECLARE #intervalMinutes int = 60
DECLARE #schedule table (
myId int primary key identity,
startTime time,
endTime time
)
DECLARE #startTime time= '12:00:00 AM';
DECLARE #endTime time='11:00:00 PM';
;WITH CTE AS
(
SELECT #startTime st
UNION ALL
SELECT DATEADD(MINUTE,#intervalMinutes,st)
FROM cte
WHERE st < DATEADD(MINUTE,#intervalMinutes,st)
)
INSERT INTO #schedule(startTime,endTime)
SELECT st, DATEADD(MINUTE,#intervalMinutes,st)FROM cte
SELECT CONVERT(varchar(10), startTime, 100) + ' - ' + CONVERT(varchar(10), endTime , 100) AS TimeSlots,
ISNULL((SELECT CASE WHEN ISNULL(O.isAfterDiscount,0) != 0 THEN ((O.SubTotal - Total_Discount) + O.Total_Tax)
ELSE ((O.SubTotal + O.Total_Tax) - Total_Discount)
END AS OrderTotal FROM [dbo].[Order] AS O WHERE O.Order_Status='COMPLETED' AND
(O.CreatedDate >= CAST(CONVERT(varchar(20), GETUTCDATE(),101) + ' ' + CONVERT(varchar(8), startTime, 108) as datetime))
AND (O.CreatedDate <= CAST(CONVERT(varchar(20), GETUTCDATE(),101) + ' ' + CONVERT(varchar(8), REPLACE(endTime,'00:00:00.000','23:59:59.999'), 108) as datetime))),0) AS TotalSales
FROM #schedule
The following error comes while execute query:
Msg 512, Level 16, State 1, Line 22
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
The following query results which I need to display:
Please guide me on this.
It means, you have got many values comes from Order table subquery. You have to apply SUM aggregate function to sum over the sales amount from order table.
SELECT CONVERT(VARCHAR(10), startTime, 100) + ' - ' + CONVERT(VARCHAR(10), endTime, 100) AS TimeSlots
,ISNULL((
SELECT SUM(CASE WHEN ISNULL(O.isAfterDiscount, 0) != 0 THEN ((O.SubTotal - Total_Discount) + O.Total_Tax) ELSE ((O.SubTotal + O.Total_Tax) - Total_Discount) END) AS OrderTotal
FROM [dbo].[Order] AS O
WHERE O.Order_Status = 'COMPLETED'
AND (O.CreatedDate >= CAST(CONVERT(VARCHAR(20), GETUTCDATE(), 101) + ' ' + CONVERT(VARCHAR(8), startTime, 108) AS DATETIME))
AND (O.CreatedDate <= CAST(CONVERT(VARCHAR(20), GETUTCDATE(), 101) + ' ' + CONVERT(VARCHAR(8), REPLACE(endTime, '00:00:00.000', '23:59:59.999'), 108) AS DATETIME))
), 0) AS TotalSales
FROM #schedule

Employee Total Experience SQL query

I have table with employees work experience. I want to get summary experience in format like yy mm dd.
e_id work_from work_to
2 2003-10-13 2004-02-12
2 2004-02-16 2004-06-30
2 2004-07-01 2006-01-31
2 2006-02-01 2017-07-12
Result should be: 13Y 8M 27D
Query like:
sum(datediff(month,work_from,work_to))/12,
sum(datediff(month,work_from,work_to)%12
works fine, but what about days?
Please note, the following query is a general summation which does not include leap years and the months are averaged between 365/12 in days since the amount of days in each month vary. If you want an exact figure that includes the exact amount of days, the algorithm will be more involved, but hopefully this gets you in a reasonably close ballpark figure.
SELECT CONVERT(VARCHAR(10), sum(datediff(year,work_from,work_to))-1) + 'Y' AS Years,
CONVERT(VARCHAR(10), FLOOR((sum(datediff(day, work_from,work_to)) - ((sum(datediff(year,work_from,work_to)) - 1) * 365)) / 30.4166)) + 'M' AS Months,
CONVERT(VARCHAR(10), CEILING(sum(datediff(day, work_from,work_to)) - ((sum(datediff(year,work_from,work_to)) - 1) * 365) - (FLOOR((sum(datediff(day, work_from,work_to)) - ((sum(datediff(year,work_from,work_to)) - 1) * 365)) / 30.4166) * 30.4166))) + 'D' AS Days,
CONVERT(VARCHAR(10), sum(datediff(day,work_from,work_to))) AS Total_Days
Here is my solution. This is the closest I can get. The problem that I had is that I cant escape the M after month.
DECLARE #SumExp Datetime = (SELECT CONCAT(
DATENAME(day, (SELECT SUM(DATEDIFF(day, WorkFrom, WorkTo))
FROM EmployeeWorkExperience)),
DATENAME(month, (SELECT SUM(DATEDIFF(day, WorkFrom, WorkTo))
FROM EmployeeWorkExperience)),
DATENAME(year, (SELECT SUM(DATEDIFF(day, WorkFrom, WorkTo))
FROM EmployeeWorkExperience))))
SELECT REPLACE(FORMAT(#SumExp, 'yyY MM# ddD'), '#', 'M')
DECLARE #work TABLE(
WorkId INT IDENTITY(1,1) PRIMARY KEY ,
work_from DATETIME NOT NULL,
work_to DATETIME NOT NULL )
INSERT INTO #work
( work_from, work_to )
VALUES ( '10/13/2003',
'2/12/2004'
),
(
'2/16/2004',
'6/30/2004'
),
('7/1/2004',
'1/31/2006'
),
('2/1/2006',
'7/12/2017'
)
DECLARE #seconds int
SELECT #seconds = SUM(DATEDIFF(SECOND, work_from, work_to))
FROM #work
DECLARE #VARDT DATETIME = DATEADD(SECOND, #seconds, 0)
SELECT CAST(DATEPART(YEAR, #VARDT) - 1900 AS VARCHAR(10)) + ' year(s) ' + CAST(DATEPART(MONTH, #VARDT) - 1 AS VARCHAR(2)) + ' month(s) '
+ CAST(DATEPART(DD, #VARDT) - 1 AS VARCHAR(2)) + ' day(s) ' + CAST(DATEPART(HOUR, #VARDT) AS VARCHAR(2)) + ' hour(s) '
+ CAST(DATEPART(MINUTE, #VARDT) AS VARCHAR(2)) + ' minute(s) ' + CAST(DATEPART(SECOND, #VARDT) AS VARCHAR(2)) + ' second(s)'

T-SQL: calculate age then add character to result

Been stuck on this one for a while now. Let's say I have a Client table like the one here:
Name BirthDayNum BirthMonthNum BirthYearNum
--------------------------------------------------
John 23 12 1965
Jane 4 9 1975
Joe 6 3 1953
Currently I am calculating the age using this syntax: (sorry if it is hard to read)
DATEDIFF(year, CONVERT(datetime, CAST(client.BirthMonthNum AS varchar(2))
+ '-' + CAST(client.BirthDayNum AS varchar(2))
+ '-' + CAST(client.BirthYearNum AS varchar(4)), 101), GETDATE())
- (CASE WHEN dateadd(YY, DATEDIFF(year, CONVERT(datetime, CAST(client.BirthMonthNum AS varchar(2))
+ '-' + CAST(client.BirthDayNum AS varchar(2))
+ '-' + CAST(client.BirthYearNum AS varchar(4)), 101), GETDATE()),
CONVERT(datetime, CAST(client.BirthMonthNum AS varchar(2))
+ '-' + CAST(client.BirthDayNum AS varchar(2))
+ '-' + CAST(client.BirthYearNum AS varchar(4)), 101)) > getdate() THEN 1 ELSE 0 END) AS 'Client Age'
This will give me the age in years. Of course if I want months, I just change the DATEDIFF(year to month. So, what I am trying to do now is this.
Continue to calculate the age, but instead of returning either years or months, I would like to return the age in years and months, but also, concat a 'y' and 'm' within the value as well. Ex. 41y 11m for Jane above.
So basically I am trying to figure out how to add a char to the return value, as well as calculate the remaining months beyond the year calculation.
Any help would be greatly appreciated!
Tired of twisting myself into knots with date calculations, I created a Table-Valued-Function to calculate elapsed time in Years, Months, Days, Hours, Minutes, and Seconds.
Example
Declare #YourTable table (Name varchar(50),BirthDayNum int, BirthMonthNum int, BirthYearNum int)
Insert Into #YourTable values
('John', 23, 12, 1965),
('Jane', 4, 9, 1975),
('Joe', 6, 3, 1953)
Select A.Name
,B.*
,Age = concat(C.Years,'y ',C.Months,'m')
From #YourTable A
Cross Apply (Select DOB = DateFromParts(A.BirthYearNum,A.BirthMonthNum,A.BirthDayNum)) B
Cross Apply [dbo].[udf-Date-Elapsed](B.DOB,GetDate()) C
Returns
Name DOB Age
John 1965-12-23 51y 3m
Jane 1975-09-04 41y 6m
Joe 1953-03-06 64y 0m
The UDF - May look like overkill, but it is very performant
CREATE FUNCTION [dbo].[udf-Date-Elapsed] (#D1 DateTime,#D2 DateTime)
Returns Table
Return (
with cteBN(N) as (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cteRN(R) as (Select Row_Number() Over (Order By (Select NULL))-1 From cteBN a,cteBN b,cteBN c),
cteYY(N,D) as (Select Max(R),Max(DateAdd(YY,R,#D1))From cteRN R Where DateAdd(YY,R,#D1)<=#D2),
cteMM(N,D) as (Select Max(R),Max(DateAdd(MM,R,D)) From (Select Top 12 R From cteRN Order By 1) R, cteYY P Where DateAdd(MM,R,D)<=#D2),
cteDD(N,D) as (Select Max(R),Max(DateAdd(DD,R,D)) From (Select Top 31 R From cteRN Order By 1) R, cteMM P Where DateAdd(DD,R,D)<=#D2),
cteHH(N,D) as (Select Max(R),Max(DateAdd(HH,R,D)) From (Select Top 24 R From cteRN Order By 1) R, cteDD P Where DateAdd(HH,R,D)<=#D2),
cteMI(N,D) as (Select Max(R),Max(DateAdd(MI,R,D)) From (Select Top 60 R From cteRN Order By 1) R, cteHH P Where DateAdd(MI,R,D)<=#D2),
cteSS(N,D) as (Select Max(R),Max(DateAdd(SS,R,D)) From (Select Top 60 R From cteRN Order By 1) R, cteMI P Where DateAdd(SS,R,D)<=#D2)
Select [Years] = cteYY.N
,[Months] = cteMM.N
,[Days] = cteDD.N
,[Hours] = cteHH.N
,[Minutes] = cteMI.N
,[Seconds] = cteSS.N
From cteYY,cteMM,cteDD,cteHH,cteMI,cteSS
)
--Max 1000 years
--Select * from [dbo].[udf-Date-Elapsed] ('1991-09-12 21:00:00.000',GetDate())
Just to Illustrate
The TVF without any secondary string manipulation would return
Select A.Name
,B.*
From #YourTable A
Cross Apply [dbo].[udf-Date-Elapsed](DateFromParts(A.BirthYearNum,A.BirthMonthNum,A.BirthDayNum),GetDate()) B
EDIT - READ ONLY VERSION
Select A.Name
,B.*
,Age = concat(DateDiff(MONTH,B.DOB,GetDate())/12,'y ',DateDiff(MONTH,B.DOB,GetDate()) % 12,'m')
From #YourTable A
Cross Apply (Select DOB = DateFromParts(A.BirthYearNum,A.BirthMonthNum,A.BirthDayNum)) B
Yes it is easier to save as DOB.. But one simple method
select concat( floor(datediff(year, datefromparts(birthyearnum,birthmonthnum,birthdaynum), getdate()))-1, 'y ', datediff(month, datefromparts(birthyearnum,birthmonthnum,birthdaynum), getdate())%12, 'm')
from #yourDates
How age for 1965 is 41y?
Input table:
create table #yourdates(Name varchar(10), BirthdayNum int, BirthMonthNum int, BirthYearNum int)
insert into #yourdates
(Name, BirthdayNum, BirthMonthNum, BirthYearNum) values
('John', 23 , 12 , 1965 )
,('Jane', 4 , 9 , 1975 )
,('Joe ', 6 , 3 , 1953 )
If you are on 2008 or lesser and can't use datefromparts...
declare #table table ([Name] varchar(4), BirthDayNum int, BirthMonthNum int, BirthYearNum int)
insert into #table
values
('John',23,12,1965),
('Jane',4,9,1975),
('Day',30,3,1990)
;with cte as(
select
[Name],
cast(BirthYearNum as varchar(4)) + '/' + cast(BirthMonthNum as varchar(2)) + '/' + cast(BirthDayNum as varchar(2)) as DOB
from
#table)
select
[Name]
,DOB
,datediff(year,DOB,GETDATE()) as Years
,datediff(month,DOB,GETDATE()) %12 as Months
,rtrim(cast(datediff(year,DOB,GETDATE()) as char(2))) + 'y ' + rtrim(cast(datediff(month,DOB,GETDATE()) %12 as char(2))) + 'm' as Age
from cte

How to CONCATENATE 2 time datatypes in sqlserver 2008?

I'm trying to concatenate two time which is start_time AND end_time and I get this error: Incorrect syntax near '+'. What I'm missing? Here is my query
SELECT schedule.sid AS [ID],
doctor.dlname + ',' + doctor.dfname + ' ' + doctor.dmname AS [Physician],
schedule.sday AS [Day],
start_time + '-' + end_time , <----I get the error here
doctor.rate AS [Rate] ,schedule.sstatus AS [Status]
FROM schedule INNER JOIN doctor ON schedule.did = doctor.did
Try this... You need to CAST start_time and end_time first before concatenating them as only string datatype is allowed to be concatenated.
SELECT schedule.sid AS [ID],
doctor.dlname + ',' + doctor.dfname + ' ' + doctor.dmname AS [Physician],
schedule.sday AS [Day],
CAST(start_time AS VARCHAR) + '-' + CAST(end_time AS VARCHAR),
doctor.rate AS [Rate] ,schedule.sstatus AS [Status]
FROM schedule
INNER JOIN doctor
ON schedule.did = doctor.did
Alternatively... you can use CONVERT too...
SELECT schedule.sid AS [ID],
doctor.dlname + ',' + doctor.dfname + ' ' + doctor.dmname AS [Physician],
schedule.sday AS [Day],
CONVERT(VARCHAR, start_time) + '-' + CONVERT(VARCHAR, end_time),
doctor.rate AS [Rate] ,schedule.sstatus AS [Status]
FROM schedule
INNER JOIN doctor
ON schedule.did = doctor.did
SELECT schedule.sid AS [ID]
,doctor.dlname + ',' + doctor.dfname + ' ' + doctor.dmname AS [Physician]
,schedule.sday AS [Day]
,CAST(start_time AS VARCHAR(8)) + '-' + CAST(end_time AS VARCHAR(8)) <----I get the error here
,doctor.rate AS [Rate]
,schedule.sstatus AS [Status]
FROM schedule INNER JOIN doctor
ON schedule.did = doctor.did
start_time is Time/Datetime datatype and '-' is a string which is varchar datatype. to concatenate two values you have to get them in the same datatype. Simply convert your concertinaing columns into character datatype.
Converting your time fields to VARCHAR(8) will return a string something like 23:13:05.

How to get sum of time field in SQL server 2008

I am facing a problem in finding the sum of values stored in a column,
I have a table like this:
gs_cycle_no | from_time | to_time | total_hours(varchar) ...
GSC-334/2012 | 13:00 | 7:00 | 42:00
GSC-334/2012 | 8:30 | 3:45 | 6:00
.
.
.
What i need to find is the Sum(total_hours) group by gs_cycle_no.
But the Sum method will not work on the varchar column and also i cant convert it to decimal due to its format,
How can i find the sum of total_hours column, based on gs_cycle_no?
if you have no minutes and only hours, then you can do something like:
select
cast(sum(cast(replace(total_hours, ':', '') as int) / 100) as nvarchar(max)) + ':00'
from Table1
group by gs_cycle_no
if you don't, try this:
with cte as
(
select
gs_cycle_no,
sum(cast(left(total_hours, len(total_hours) - 3) as int)) as h,
sum(cast(right(total_hours, 2) as int)) as m
from Table1
group by gs_cycle_no
)
select
gs_cycle_no,
cast(h + m / 60 as nvarchar(max)) + ':' +
right('00' + cast(m % 60 as nvarchar(max)), 2)
from cte
sql fiddle demo
This will work:
;with times as (
select gs_cycle_no = 'GSC-334/2012', total_hours = '8:35'
union all SELECT gs_cycle_no = 'GSC-334/2012', '5:00'
union all SELECT gs_cycle_no = 'GSC-334/2012', '16:50'
union all SELECT gs_cycle_no = 'GSC-334/2012', '42:00'
union all SELECT gs_cycle_no = 'GSC-335/2012', '0:00'
union all SELECT gs_cycle_no = 'GSC-335/2012', '175:52'
union all SELECT gs_cycle_no = 'GSC-335/2012', '12:25')
SELECT
gs_cycle_no,
hrs = sum(mins) / 60 + sum(hrs),
mins = sum(mins) % 60
FROM
TIMES
cross apply(
select c = charindex(':', total_hours)
) idx
cross apply(
select
hrs = cast(substring(total_hours, 1, c - 1) as int),
mins = cast(substring(total_hours, c + 1, len(total_hours)) as int)
) ext
group by gs_cycle_no
order by gs_cycle_no
This query finds sum in minutes:
SQLFiddle demo
select gs_cycle_no,
SUM(
CAST(
ISNULL(
substring(total_hours,1,CHARINDEX(':',total_hours)-1)
,'0') as INT) * 60
+
CAST(
ISNULL(
substring(total_hours,CHARINDEX(':',total_hours)+1,100)
,'0') as INT)
)
from t
group by gs_cycle_no
Here is solution where I break varchar into two small pieces, hours and minutes, and then make minutes from them, and at last, SUM them:
SELECT
gs_cycle_no,
CAST(SUM(
SUBSTRING(total_hours,0 ,CHARINDEX(':', total_hours)) * 60 +
SUBSTRING(total_hours, CHARINDEX(':', total_hours) + 1, LEN(total_hours))) / 60 AS VARCHAR) + ':' +
CAST(SUM(
SUBSTRING(total_hours,0 ,CHARINDEX(':', total_hours)) * 60 +
SUBSTRING(total_hours, CHARINDEX(':', total_hours) + 1, LEN(total_hours))) % 60 AS VARCHAR)
FROM Table1
GROUP BY gs_cycle_no