SQL将开/关(位)分组在一起以计算持续时间
使用SQLServer2008+ 不确定如何提问,因此以下是一些示例数据:SQL将开/关(位)分组在一起以计算持续时间,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,使用SQLServer2008+ 不确定如何提问,因此以下是一些示例数据: case_id start_time timer_name type value duration 8386 2013-02-01 19:25:52 Patient In 25 1 NULL 8386 2013-02-01 20:18:31 Patient Out 25 0 NULL 8386 2013-02-01 20:13:
case_id start_time timer_name type value duration
8386 2013-02-01 19:25:52 Patient In 25 1 NULL
8386 2013-02-01 20:18:31 Patient Out 25 0 NULL
8386 2013-02-01 20:13:13 Anes. Start 26 1 NULL
8386 2013-02-01 20:18:37 Anes. Stop 26 0 NULL
8386 2013-02-01 20:13:25 Induction 27 1 NULL
8386 2013-02-01 20:18:41 Emergence 27 0 NULL
8386 2013-02-01 20:13:31 Incision 28 1 NULL
8386 2013-02-01 20:18:45 Closing 28 0 NULL
8451 2013-02-06 18:37:44 Anesthesia 1 1 NULL
8451 2013-02-06 18:37:48 Incision 1 1 NULL
8451 2013-02-06 18:05:32 Patient In 25 1 NULL
8451 2013-02-06 18:07:41 Anes. Start 26 1 NULL
8451 2013-02-06 18:11:00 Induction 27 1 NULL
8451 2013-02-06 18:11:54 Emergence 27 0 NULL
8451 2013-02-06 18:11:20 Incision 28 1 NULL
以下是我用来生成此列表的SQL:
SELECT case_id, start_time, timer_name, type, value, duration
FROM dbo.event AS ev WITH (nolock)
WHERE (type IN (1, 2, 3, 25, 26, 27, 28)) AND (defunct = 'N')
ORDER BY case_id, type, start_time
我需要做的是将类型分组,按case\u id、type和start\u time排序,然后计算第一个值为1的条目与下一个值为0的相同类型条目之间的持续时间。
在上述数据中,案例8386应具有以下数据:
8386 2013-02-01 19:25:52 Patient In 25 1 52:39
8386 2013-02-01 20:13:13 Anes. Start 26 1 5:24
8386 2013-02-01 20:13:25 Induction 27 1 5:16
8386 2013-02-01 20:13:31 Incision 28 1 5:14
希望我算对了。持续时间不需要采用该格式。我希望秒数是最好的,但这种格式在问题中更容易阅读。计时器名称字段中显示的名称也无关紧要
请理解,我可能会在一行中为一个类型获取多个1值,或者在一行中获取多个0值。我需要将第一个1与第一个0联系起来,计算持续时间,然后查找下一个1,等等。这意味着每种类型、每种情况可能有几个分组。如果没有为1值找到0值,则我将使用可以从另一个表中提取的case\u end\u时间。此版本的查询使用相关子查询根据您的逻辑查找下一个开始时间。在SQL Server 2012中,这将使用
lead()
函数,但该函数不可用:
select case_id, start_time, timer_name, type, value, duration,
(select top 1 start_time
from event e2
where e2.case_id = e.case_id and e2.type = e.type and e2.value = 0 and
e2.start_time > e.start_time
order by start_time desc
) - start_time as duration
from event e
WHERE (type IN (1, 2, 3, 25, 26, 27, 28)) AND (defunct = 'N') and value = 1
您的示例没有多个“0”。如果您只想要第一个,我们可以使用row\u number()
:
好的,你必须使用一些东西,首先,要得到第一个1和0,你需要使用一个按值划分的行数函数,这样你就不能使用where子句按行=1进行过滤。在这一点上,您将获得每个案例的1和0中的第一个。如果在单独的查询中执行此操作,则可以将它们连接起来,并在两个日期之间使用差分函数。像这样的事情:
SELECT
case_id, type, DATEDIFF(mm, a.start_time, b.start_time) duration
FROM
(SELECT case_id, start_time, timer_name, type, value, duration
FROM dbo.event AS ev WITH (nolock)
WHERE (type IN (1, 2, 3, 25, 26, 27, 28)) AND (defunct = 'N')
AND ROW_NUMBER() OVER(PARTITION BY type, value ORDER BY case_id, type) = 1 --Get the first row only
AND TYPE = 0 -- And the ones of type 0
) a INNER JOIN
(SELECT case_id, start_time, timer_name, type, value, duration
FROM dbo.event AS ev WITH (nolock)
WHERE (type IN (1, 2, 3, 25, 26, 27, 28)) AND (defunct = 'N')
AND ROW_NUMBER() OVER(PARTITION BY type, value ORDER BY case_id, type) = 1 --Get the first row only
AND TYPE = 1 -- And the ones of type 1
) b
ON
a.case_id = b.case_id AND
a.[type] = b.[type]
我还没有测试它,但这就是想法这是SQLServer,还是另一个RDBMS?使用SQLServer2008。在问题中也加入了这一点。谢谢我仍然在关注它,因为这看起来是正确的方向,但按原样运行SQL总是将下一个开始时间/持续时间返回为null。value=0的where子句是否会过滤掉所有的1,以便“select top 1…e2.value=1…”永远不会返回任何内容?@mdutra。我翻转了0和1的值。我刚把这个修好。
SELECT
case_id, type, DATEDIFF(mm, a.start_time, b.start_time) duration
FROM
(SELECT case_id, start_time, timer_name, type, value, duration
FROM dbo.event AS ev WITH (nolock)
WHERE (type IN (1, 2, 3, 25, 26, 27, 28)) AND (defunct = 'N')
AND ROW_NUMBER() OVER(PARTITION BY type, value ORDER BY case_id, type) = 1 --Get the first row only
AND TYPE = 0 -- And the ones of type 0
) a INNER JOIN
(SELECT case_id, start_time, timer_name, type, value, duration
FROM dbo.event AS ev WITH (nolock)
WHERE (type IN (1, 2, 3, 25, 26, 27, 28)) AND (defunct = 'N')
AND ROW_NUMBER() OVER(PARTITION BY type, value ORDER BY case_id, type) = 1 --Get the first row only
AND TYPE = 1 -- And the ones of type 1
) b
ON
a.case_id = b.case_id AND
a.[type] = b.[type]