我必须关注数据:
| tid | startdate | enddate |
| 1 | 2016-12-26 12:30 | 2016-12-26 15:30 |
| 2 | 2016-12-26 13:15 | 2016-12-26 15:15 |
我想创建一个带有小时数的结果,然后是该小时内日期时间的分钟数。
示例结果:
| tid | hour | minutes_in |
| 1 | 12 | 30 |
| 1 | 13 | 60 |
| 1 | 14 | 60 |
| 1 | 15 | 30 |
| 2 | 13 | 45 |
| 2 | 14 | 60 |
| 2 | 15 | 15 |
有什么建议吗?
答案 0 :(得分:5)
首先,您需要一个数字表来获取0到23之间的小时数,这可以通过表值构造函数轻松创建:
SELECT N
FROM (VALUES
(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),
(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23)
) n (N);
然后,您可以将其与原始数据相连,以将行拆分为所需的数字。然后你只需要一个case表达式来应用正确的逻辑来计算分钟:
WITH Numbers (Number) AS
( SELECT N
FROM (VALUES
(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),
(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23)
) n (N)
), SampleData (tid, StartDate, EndDate) AS
( SELECT tid, CONVERT(DATETIME2, StartDate), CONVERT(DATETIME2, EndDate)
FROM (VALUES
(1, '2016-12-26 12:30', '2016-12-26 15:30'),
(2, '2016-12-26 13:15', '2016-12-26 15:15')
) d (tid, StartDate, EndDate)
)
SELECT d.tid,
[Hour] = n.Number,
Minutes_in = CASE
-- SPECIAL CASE: START HOUR = END HOUR
WHEN DATEPART(HOUR, d.StartDate) = DATEPART(HOUR, d.EndDate)
THEN DATEDIFF(MINUTE, d.StartDate, d.EndDate)
-- FULL HOURS IN BETWEEN START AND END
WHEN n.Number > DATEPART(HOUR, d.StartDate)
AND n.Number < DATEPART(HOUR, d.EndDate) THEN 60
-- START HOUR
WHEN n.Number = DATEPART(HOUR, d.StartDate)
THEN 60 - DATEPART(MINUTE, d.StartDate)
-- END HOUR
WHEN n.Number = DATEPART(HOUR, d.EndDate)
THEN DATEPART(MINUTE, d.EndDate)
END
FROM SampleData d
INNER JOIN Numbers n
ON n.Number >= DATEPART(HOUR, d.StartDate)
AND n.Number <= DATEPART(HOUR, d.EndDate);
<强>附录强>
如果您需要跨越几天,那么您可以稍微改变逻辑,生成一组更大的数字以覆盖更多的小时差异,然后加入小时差异的数字,而不是加入小时差异。将datetime开始到结束日期时间:
SELECT *
FROM SampleData d
INNER JOIN Numbers n
ON n.Number <= DATEDIFF(HOUR, d.StartDate, d.EndDate)
这意味着范围跨越几天,然后没有问题,小时数不断增加。 e.g。
WITH Numbers (Number) AS
( SELECT ROW_NUMBER() OVER(ORDER BY N1.N) - 1
FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N1(N)
CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N2 (N)
CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N3 (N)
CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N4 (N)
), SampleData (tid, StartDate, EndDate) AS
( SELECT tid, CONVERT(DATETIME2, StartDate), CONVERT(DATETIME2, EndDate)
FROM (VALUES
(1, '2016-12-26 12:30', '2016-12-26 15:30'),
(2, '2016-12-26 13:15', '2016-12-26 15:15'),
(3, '2016-12-26 13:15', '2016-12-27 15:15')
) d (tid, StartDate, EndDate)
)
SELECT d.tid,
[Date] = CONVERT(DATE, d.StartDate),
[Hour] = CONVERT(TIME(0), DATEADD(HOUR, DATEPART(HOUR, d.StartDate) + n.Number, 0)),
Minutes_in = CASE
-- SPECIAL CASE: START HOUR = END HOUR
WHEN DATEPART(HOUR, d.StartDate) = DATEPART(HOUR, d.EndDate)
AND DATEDIFF(DAY, d.StartDate, d.EndDate) = 0
THEN DATEDIFF(MINUTE, d.StartDate, d.EndDate)
-- START HOUR
WHEN n.Number = 0
THEN 60 - DATEPART(MINUTE, d.StartDate)
-- END HOUR
WHEN n.Number = DATEDIFF(HOUR, d.StartDate, d.EndDate)
THEN DATEPART(MINUTE, d.EndDate)
-- FULL HOURS IN BETWEEN START AND END
ELSE 60
END
FROM SampleData d
INNER JOIN Numbers n
ON n.Number <= DATEDIFF(HOUR, d.StartDate, d.EndDate)
ORDER BY d.tid, n.Number;
答案 1 :(得分:0)
方法-I
您可以使用UDF(另一种最简单的方法)实现此目的
让您提供所提供数据的架构
[ 'CAP5x5',
20,
'OdinUnranked',
256,
'Unranked',
1964,
'RankedSolo5x5',
101 ]
创建一个UDF以生成from和To之间的值
CREATE TABLE #TAB ( TID INT, STARTDATE DATETIME, ENDDATE DATETIME)
INSERT INTO #TAB
SELECT 1,'2016-12-26 12:30','2016-12-26 15:30'
UNION ALL
SELECT 2,'2016-12-26 13:15','2016-12-26 15:15'
现在通过调用函数来查询数据。
ALTER FUNCTION [dbo].[FN_GENERATE] (@FROM_NBR INT, @TO_NBR INT)
RETURNS
@RESULT TABLE(HR INT)
AS
BEGIN
;WITH CTE AS
(
SELECT @FROM_NBR AS FROM_NBR,@TO_NBR AS TO_NBR
UNION ALL
SELECT FROM_NBR+1 ,TO_NBR FROM CTE WHERE FROM_NBR<TO_NBR
)
INSERT INTO @RESULT
SELECT FROM_NBR FROM CTE
RETURN
END
编辑:
方法 - II
不使用UDF&amp;使用;WITH CTE AS (
SELECT TID,STARTDATE,ENDDATE,DATEPART(HH,STARTDATE) FROM_HR , DATEPART(HH,ENDDATE) TO_HR FROM #TAB T
)
SELECT C1.TID,F.HR, COALESCE(DATEPART(MINUTE,FRM_HR_MINUTS.STARTDATE),DATEPART(MINUTE,TO_HR_MINUTS.ENDDATE),60 )
FROM CTE C1
CROSS APPLY
(
SELECT * FROM DBO.[FN_GENERATE] (C1.FROM_HR, C1.TO_HR)
)AS F
LEFT JOIN CTE FRM_HR_MINUTS ON C1.TID= FRM_HR_MINUTS.TID AND DATEPART(HH,FRM_HR_MINUTS.STARTDATE)= F.HR
LEFT JOIN CTE TO_HR_MINUTS ON C1.TID= TO_HR_MINUTS.TID AND DATEPART(HH,TO_HR_MINUTS.ENDDATE)= F.HR
MASTER.DBO.SPT_VALUES