【问题标题】:SQL: A Grouping and Counting puzzleSQL:分组和计数难题
【发布时间】:2018-09-13 02:40:22
【问题描述】:

以下是用户列表示例,以及他们开始公交旅程的车站/时间和结束的车站/时间:

user    Ststation   Starttime   endstation  endtime
bgh567  StationA    5:00:00     StationB    7:00:00
abc645  StationD    4:00:00     StationX    4:15:00
yh564   StationG    2:00:00     StationA    17:00:00
Yghf78  StationB    6:00:00     StationC    2:45:00

...这个列表要长得多,而且是全天的。

我的目标是计算每个站点每隔 15 分钟开始和结束每个站点的旅程的用户数量。所以结果看起来像这样(我所做的计数是样本,并不代表本文中的样本表):

Time    Station     Enter   Exit
2:00:00 StationA    1      0
2:15:00 StationA    58     23
2:45:00 StationA    36     78
3:00:00 StationA    0      76

... 以此类推。然后当 StationA 完成后,会计算 StationB,以此类推。

我已经能够通过这样的查询获得每个相应的计数:

SELECT starttime, ststation, COUNT(user) as count_enter
  FROM sourcetable 
  GROUP BY starttime, ststation 
  ORDER BY ststation, starttime

还有一个类似的退出计数。但是我遇到了将它们连接在一起以创建上述最终结果的问题。我在 Spark SQL 中执行此操作,但如果我了解该方法,我可以针对我的环境定制任何响应。有什么想法吗?

【问题讨论】:

  • edit您的问题标题实际上描述了您遇到的问题或您提出的问题。标题应该足够清晰,以供正在扫描搜索结果列表以解决问题的未来用户使用。你的没有提供这方面的任何有用信息。谢谢。
  • 请添加您的 RDBMS 标签!
  • 众所周知,日期/时间函数依赖于数据库。没有数据库标签,回答这个问题是不可行的。

标签: sql join group-by count


【解决方案1】:

这是对Oracle 的查询。更改用于相应 RDBMS 的函数:

WITH table_name AS 
(
    SELECT 'bgh567' AS user_name, 'StationA' AS station, sysdate + 1/(24*60) AS starttime, 'StationB' AS endstation, sysdate + 18/(24*60) AS endtime FROM dual UNION ALL
    SELECT 'abc645'AS user_name , 'StationD' AS station, sysdate + 15/(24*60) AS starttime, 'StationX' AS endstation, sysdate + 17/(24*60) AS endtime FROM dual UNION ALL
    SELECT 'yh564' AS user_name , 'StationG' AS station, sysdate + 12/(24*60) AS starttime, 'StationA' AS endstation, sysdate + 28/(24*60) AS endtime FROM dual UNION ALL
    SELECT 'Yghf78'AS user_name , 'StationB' AS station, sysdate + 13/(24*60) AS starttime, 'StationC' AS endstation, sysdate + 19/(24*60) AS endtime FROM dual 
)
, enter_table AS
(
    SELECT 
        TO_CHAR(starttime, 'yyyy/mm/dd') || ' ' || TO_CHAR(starttime, 'hh24') 
            || ':' || TO_CHAR(FLOOR(TO_CHAR(starttime, 'MI') / 15) * 15, 'FM00') 
            || ':00' AS time_interval,
        station,
        COUNT(*) AS enter
    FROM table_name
    GROUP BY TO_CHAR(starttime, 'yyyy/mm/dd'),
        TO_CHAR(starttime, 'hh24'),
        FLOOR(TO_CHAR(starttime, 'MI') / 15),
        station
)
, exit_table AS
(
    SELECT 
        TO_CHAR(endtime, 'yyyy/mm/dd') || ' ' || TO_CHAR(endtime, 'hh24') 
            || ':' || TO_CHAR(FLOOR(TO_CHAR(endtime, 'MI') / 15) * 15, 'FM00') 
            || ':00' AS time_interval,
        endstation AS station,
        COUNT(*) AS exit
    FROM table_name
    GROUP BY TO_CHAR(endtime, 'yyyy/mm/dd'),
        TO_CHAR(endtime, 'hh24'),
        FLOOR(TO_CHAR(endtime, 'MI') / 15),
        endstation
)

SELECT
    COALESCE(e.time_interval, ex.time_interval) AS time_interval, 
    COALESCE(e.station, ex.station) AS station,
    COALESCE(e.enter, 0) AS enter,
    COALESCE(ex.exit , 0) AS exit 
FROM enter_table e
FULL OUTER JOIN exit_table ex
ON e.time_interval = ex.time_interval
    AND e.station = ex.station
ORDER BY 1, 2;

【讨论】:

  • 嗨范非常感谢!实际上我今天早上用和你在这里做的一样的方法想通了!一旦我发现了 COALESCE 函数,它就非常简单了。
猜你喜欢
  • 1970-01-01
  • 2013-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-11
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
相关资源
最近更新 更多