【问题标题】:TRANSACT SQL Generate multiple rows from DateDiffTRANSACT SQL 从 DateDiff 生成多行
【发布时间】:2012-12-12 16:26:55
【问题描述】:

我有下表

table event(
   start_tstamp [datetime],
   stop_tstamp [datetime],
   exe_name [nvarchar](50),
   machine_name [nvarchar](30)
)

我需要从该表中生成一个标量表,其中包含以下形式的 start_tstampstop_tstamp 之间每小时差异的一行信息:

table event_temp(
   day_occured [datetime],
   hour_occured [tinyint],
   exe_name [nvarchar](50),
   machine_name [nvarchar](30)
)

例如表事件包含两行

"2012/12/10 07:00", "2012/12/10 09:00", "notepad.exe", "testmachine"
"2012/12/11 15:00", "2012/12/11 18:00", "notepad.exe", "foomachine"

生成的 event_temp 应该如下

"2012/12/10 00:00", 7, "notepad.exe", "testmachine"
"2012/12/10 00:00", 8, "notepad.exe", "testmachine"
"2012/12/10 00:00", 9, "notepad.exe", "testmachine"
"2012/12/11 00:00", 15, "notepad.exe", "foomachine"
"2012/12/11 00:00", 16, "notepad.exe", "foomachine"
"2012/12/11 00:00", 17, "notepad.exe", "foomachine"
"2012/12/11 00:00", 18, "notepad.exe", "foomachine"

然后我需要将 event_temp 表与一个现有的日历表连接起来,该表返回与 event_temp

中的日期匹配的日期列表
table calendar(
   day_occured [datetime],
   hour_occured [tinyint],
)

那将只包含:

"2012/12/10 00:00", 0
"2012/12/10 00:00", 1
"2012/12/10 00:00", 2
"2012/12/10 00:00", 3
"2012/12/10 00:00", 4
"2012/12/10 00:00", 5
...

结果基本上应该是一个在特定时间运行的记事本实例的列表。

table result(
   day_occured [datetime],
   hour_occured [tinyint],
   instances_running [int]
)

有什么想法可以做到这一点吗?

【问题讨论】:

  • 如果你有一个datetime(这意味着我们都可能会认为这是 SQL Server,对吗?),你为什么有hour_occured 列?
  • 事件中的日期可以跨越一天吗?
  • 一旦你有了 event_Temp 你就可以使用count(distinct machine_name) as instances_running / group by day, hour,对吧?我不明白你为什么需要日历表。
  • @Clockwork-Muse:不幸的是,这是应用程序的预期输入,我无法修改应用程序本身,是的,它是 SQL Server Transact SQL。
  • @Beth:是的,可能是这样。如果在特定小时内没有条目,则应用程序会将结果转换为图表,然后图表的线条会出现断线。日历表由应用程序生成和维护。

标签: sql sql-server database datediff


【解决方案1】:

编辑:正如 Clockwork-Muse 指出的那样,我的最后一个答案有一些缺陷。这是一种不同的方法。

不包括零小时...

DECLARE @MinDate datetime = (SELECT TOP 1 start_tstamp FROM [event] ORDER BY start_tstamp ASC)
DECLARE @MaxDate datetime = (SELECT TOP 1 stop_tstamp FROM [event] ORDER BY stop_tstamp DESC)

WITH Dates AS (
    SELECT @MinDate AS dt
    UNION ALL
    SELECT DATEADD(hh, 1, dt)
      FROM Dates s
     WHERE DATEADD(hh, 1, dt) <= @MaxDate)

SELECT 
  CONVERT(date,d.dt,101) AS [day_occured],
  DATEPART(hh, d.dt) AS [hour_occured],
  COUNT(*) AS [instances_running]
FROM @Event e
JOIN Dates d ON e.start_tstamp <= d.dt
        AND e.stop_tstamp  > = d.dt 
GROUP BY d.dt
OPTION (MAXRECURSION 0)

包括零小时...

SET @MinDate = CONVERT(date,@MinDate,101)
SET @MaxDate = CONVERT(date, DATEADD(dd,1,@MaxDate))
SET @MaxDate = DATEADD(MILLISECOND, -2,@MaxDate)

SELECT 
  CONVERT(date,d.dt,101) AS [day_occured],
  DATEPART(hh, d.dt) AS [hour_occured],
  SUM(CASE ISNULL(exe_name,'-1') WHEN '-1' THEN 0 ELSE 1 END ) AS [instances_running]
FROM [event] e
FULL JOIN Dates d ON e.start_tstamp <= d.dt
         AND e.stop_tstamp  >= d.dt 
GROUP BY d.dt
OPTION (MAXRECURSION 0)

【讨论】:

  • 好吧,你的比较顺序让我失望了。两件事:1)没有'24'小时这样的东西,它是'0'小时(第二天)。 2) 这不适用于任何跨越日期边界的事件(在您回答后发布的评论中表明这是可能的)。另外,我不确定,但我认为 OP 可能还想要 '0-count' 行......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-16
  • 2017-05-13
  • 1970-01-01
  • 1970-01-01
  • 2022-12-17
相关资源
最近更新 更多