英文:
SQL - Find cycle and duration
问题
我在SQL(postgresql)中寻找解决方案来解决我的问题。
我有一个包含以下列的日志表:
设备ID | ID | 代码 | 时间戳 |
---|---|---|---|
device1 | 1 | 12 | 1672597471000 |
device1 | 2 | 11 | 1672597471001 |
device1 | 3 | 8 | 1672597471002 |
device1 | 4 | 2 | 1672597471003 |
device1 | 5 | 9 | 1672597471004 |
device1 | 6 | 9 | 1672597471005 |
device1 | 7 | 4 | 1672597471006 |
device1 | 8 | 8 | 1672597471007 |
device1 | 9 | 9 | 1672597471008 |
device2 | 1 | 8 | 1672597471000 |
device2 | 2 | 9 | 1672597471010 |
device2 | 3 | 12 | 1672597471050 |
device2 | 4 | 8 | 1672597471100 |
device2 | 5 | 9 | 1672597471130 |
我寻找一个查询(或多个查询)来查找两个代码之间的经过的时间(例如8和9)。
SQL查询的输出将如下:
设备ID | 经过的时间 |
---|---|
device1 | 2 |
device1 | 1 |
device2 | 10 |
device2 | 30 |
如果有人能提供一些解决这个问题的想法,我将不胜感激。
我尝试过使用lead
函数,但无法在每个序列(8和9)之间重置时间,并忽略唯一的8或9。简而言之,我陷入了困境,不知道在SQL中是否有可能实现这一目标。
英文:
I search a solution for my problem in SQL (postgresql).
I have a logs table with the following columns:
deviceId | id | code | timestamp |
---|---|---|---|
device1 | 1 | 12 | 1672597471000 |
device1 | 2 | 11 | 1672597471001 |
device1 | 3 | 8 | 1672597471002 |
device1 | 4 | 2 | 1672597471003 |
device1 | 5 | 9 | 1672597471004 |
device1 | 6 | 9 | 1672597471005 |
device1 | 7 | 4 | 1672597471006 |
device1 | 8 | 8 | 1672597471007 |
device1 | 9 | 9 | 1672597471008 |
device2 | 1 | 8 | 1672597471000 |
device2 | 2 | 9 | 1672597471010 |
device2 | 3 | 12 | 1672597471050 |
device2 | 4 | 8 | 1672597471100 |
device2 | 5 | 9 | 1672597471130 |
I search one query (or more) to find the time elapsed between two codes (8 and 9 for example).
The output of SQL query will be:
deviceId | elapsed time |
---|---|
device1 | 2 |
device1 | 1 |
device2 | 10 |
device2 | 30 |
I would really appreciate if anyone can suggest some ideas how to solve this problem.
I tried with lead function but i can't reset time between each sequence (8 and 9) and ignore unique 8 or 9. In short, i'm stuck and I don't know if it's possible in SQL.
答案1
得分: 1
以下是已翻译好的内容:
可以通过使用窗口函数 lag()
来获取当前行的前一行,然后通过减法来获取 8 和 9 之间的经过时间,条件是 where code = 9 and lag_code = 8
:
with cte as (
select *,
lag(timestamp) over (partition by deviceid order by timestamp) as lag_timestamp,
lag(code) over (partition by deviceid order by timestamp) as lag_code
from mytable
where code between 8 and 9
)
select deviceId, timestamp - lag_timestamp as elapsed_time
from cte
where code = 9 and lag_code = 8
结果:
deviceid | elapsed_time |
---|---|
device1 | 2 |
device1 | 1 |
device2 | 10 |
device2 | 30 |
英文:
This can be accomplished by using the window function lag()
to obtain the previous row of the current row, followed by subtraction to obtain the elapsed time between 8 and 9 using the condition where code = 9 and lag_code = 8
:
with cte as (
select *,
lag(timestamp) over (partition by deviceid order by timestamp) as lag_timestamp,
lag(code) over (partition by deviceid order by timestamp) as lag_code
from mytable
where code between 8 and 9
)
select deviceId, timestamp - lag_timestamp as elapsed_time
from cte
where code = 9 and lag_code = 8
Result :
deviceid | elapsed_time |
---|---|
device1 | 2 |
device1 | 1 |
device2 | 10 |
device2 | 30 |
答案2
得分: 0
使用以下简单查询来获取您所需的结果(并在fiddle上进行测试):
select a.deviceId, (b.timestamp - a.timestamp) as elapsed_time
from logs a join logs b
on b.deviceid = a.deviceid
and b.id = (select min(id)
from logs b
where b.deviceid = a.deviceid
and b.id > a.id
and code = 9)
where a.code = 8;
查询结果如下:
deviceid | elapsed_time
----------+--------------
device1 | 2
device1 | 1
device2 | 10
device2 | 30
英文:
Use this simple query to produce the result you need (and test it on fiddle) :
select a.deviceId, (b.timestamp - a.timestamp) as elapsed_time
from logs a join logs b
on b.deviceid = a.deviceid
and b.id = (select min(id)
from logs b
where b.deviceid = a.deviceid
and b.id > a.id
and code = 9)
where a.code = 8;
and it gives:
deviceid | elapsed_time
----------+--------------
device1 | 2
device1 | 1
device2 | 10
device2 | 30
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论