Oracle SQL查询 – 两个时间戳之间

huangapple go评论52阅读模式
英文:

Oracle SQL Query - Between Two Timestamp

问题

对于一份报告,我需要根据他们的活动,跟踪人员在给定时间范围内从一个地方到另一个地方的移动。

从上表中,假设我们需要跟踪人们从上午8点到晚上8点(08:00至20:00)的移动,结果如下:

使用WHERE子句中的BETWEEN可以获取在给定范围内的活动。但我无法获取每个人的第一个“出发地”,因为它超出了时间范围。我尝试过使用GROUP BY和窗口函数,但仍然无法获得所需的结果。有人可以帮忙吗?

姓名 出发地 目的地
Peter ????? 餐厅
Peter 餐厅 办公室
Peter 办公室 高尔夫
John ????? 健身房
John 健身房 剧院
John 剧院 足球场
英文:

For a report, i need to track movement of persons from one place to another within a given time range, based on their activities

Activities

Name TimeStamp Activity
Peter 10-JAN-23 05:23:06 Gym
Peter 10-JAN-23 07:01:45 Home
Peter 10-JAN-23 08:09:26 Restaurant
Peter 10-JAN-23 09:19:32 Office
Peter 10-JAN-23 16:43:02 Golf
John 10-JAN-23 07:30:26 Home
John 10-JAN-23 08:30:43 Gym
John 10-JAN-23 10:02:06 Theater
John 10-JAN-23 12:00:32 Soccer
John 10-JAN-23 20:23:02 Bar

From the above table, let's say we need to track movement of people from 8AM to 8PM (08:00 to 20:00) the result would be as below.

Name From To
Peter Home Restaurant
Peter Restaurant Office
Peter Office Golf
John Home Gym
John Gym Theater
John Theater Soccer

Using BETWEEN in WHERE CLAUSE the activity between the given range can be fetched. But I am unable to get the first 'FROM' place of each person as it falls outside the time range. I have tried with group by and window functions, but still unable to get the desired result. Can someone please help on this ?

Name From To
Peter ????? Restaurant
Peter Restaurant Office
Peter Office Golf
John ????? Gym
John Gym Theater
John Theater Soccer

答案1

得分: 2

使用内部查询中的LAG分析函数,然后在外部查询中按时间范围进行筛选(如果您反过来做,那么您将在使用LAG查找之前过滤掉范围开始之前的值):

SELECT name,
       prev_activity AS "FROM",
       activity AS "TO"
FROM   (
  SELECT a.*,
         LAG(activity) OVER (PARTITION BY name ORDER BY timestamp) AS prev_activity
  FROM   activities a
)
WHERE  timestamp BETWEEN TIMESTAMP '2023-01-10 08:00:00'
                     AND TIMESTAMP '2023-01-10 20:00:00';

对于示例数据:

CREATE TABLE activities ( Name, TimeStamp, Activity ) AS
SELECT 'Peter', TIMESTAMP '2023-01-10 05:23:06', 'Gym' FROM DUAL UNION ALL
SELECT 'Peter', TIMESTAMP '2023-01-10 07:01:45', 'Home' FROM DUAL UNION ALL
SELECT 'Peter', TIMESTAMP '2023-01-10 08:09:26', 'Restaurant' FROM DUAL UNION ALL
SELECT 'Peter', TIMESTAMP '2023-01-10 09:19:32', 'Office' FROM DUAL UNION ALL
SELECT 'Peter', TIMESTAMP '2023-01-10 16:43:02', 'Golf' FROM DUAL UNION ALL
SELECT 'John', TIMESTAMP '2023-01-10 07:30:26', 'Home' FROM DUAL UNION ALL
SELECT 'John', TIMESTAMP '2023-01-10 08:30:43', 'Gym' FROM DUAL UNION ALL
SELECT 'John', TIMESTAMP '2023-01-10 10:02:06', 'Theater' FROM DUAL UNION ALL
SELECT 'John', TIMESTAMP '2023-01-10 12:00:32', 'Soccer' FROM DUAL UNION ALL
SELECT 'John', TIMESTAMP '2023-01-10 20:23:02', 'Bar' FROM DUAL;

输出结果:

NAME FROM TO
John Home Gym
John Gym Theater
John Theater Soccer
Peter Home Restaurant
Peter Restaurant Office
Peter Office Golf

fiddle

英文:

Use the LAG analytic function in an inner-query and then filter on the time range in an outer query (if you do it the other way round then you will filter out the value before the start of the range before you can find it using LAG):

SELECT name,
       prev_activity AS "FROM",
       activity AS "TO"
FROM   (
  SELECT a.*,
         LAG(activity) OVER (PARTITION BY name ORDER BY timestamp) AS prev_activity
  FROM   activites a
)
WHERE  timestamp BETWEEN TIMESTAMP '2023-01-10 08:00:00'
                     AND TIMESTAMP '2023-01-10 20:00:00';

Which, for the sample data:

CREATE TABLE activities ( Name, TimeStamp, Activity ) AS
SELECT 'Peter',	TIMESTAMP '2023-01-10 05:23:06',	'Gym' FROM DUAL UNION ALL
SELECT 'Peter',	TIMESTAMP '2023-01-10 07:01:45',	'Home' FROM DUAL UNION ALL
SELECT 'Peter',	TIMESTAMP '2023-01-10 08:09:26',	'Restaurant' FROM DUAL UNION ALL
SELECT 'Peter',	TIMESTAMP '2023-01-10 09:19:32',	'Office' FROM DUAL UNION ALL
SELECT 'Peter',	TIMESTAMP '2023-01-10 16:43:02',	'Golf' FROM DUAL UNION ALL
SELECT 'John',	TIMESTAMP '2023-01-10 07:30:26',	'Home' FROM DUAL UNION ALL
SELECT 'John',	TIMESTAMP '2023-01-10 08:30:43',	'Gym' FROM DUAL UNION ALL
SELECT 'John',	TIMESTAMP '2023-01-10 10:02:06',	'Theater' FROM DUAL UNION ALL
SELECT 'John',	TIMESTAMP '2023-01-10 12:00:32',	'Soccer' FROM DUAL UNION ALL
SELECT 'John',	TIMESTAMP '2023-01-10 20:23:02',	'Bar' FROM DUAL;

Outputs:

NAME FROM TO
John Home Gym
John Gym Theater
John Theater Soccer
Peter Home Restaurant
Peter Restaurant Office
Peter Office Golf

fiddle

答案2

得分: 1

使用窗口函数 LAG(activity)LEAD(activity) OVER (PARTITION BY name ORDER BY timestamp) 来显示前一个(或下一个)位置。这就是你的FROM(或TO,无论你喜欢哪个)。完成。

英文:

Use the windowing LAG(activity) or LEAD(activity) OVER (PARTITION BY name ORDER BY timestamp) to show the previous (or next) location. That's your FROM (or TO, whichever you prefer). Done.

huangapple
  • 本文由 发表于 2023年2月13日 23:16:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/75437771.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定