【问题标题】:Group Date column based on hours基于小时的分组日期列
【发布时间】:2014-05-06 10:14:10
【问题描述】:

我在 sqlite 数据库中有一个表,用于存储有关通话记录的数据。举个例子,假设我的表是这样的

| Calls_count | Calls_duration | Time_slice | Time_stamp |
|    10       |     500        | 21         | 1399369269 |
|     2       |     88         | 22         | 1399383668 |    

这里

Calls_count 是自上次观察以来的通话次数

Calls_duration 是自上次观察以来的通话持续时间,以毫秒为单位

时间片表示一周的时间部分。每天分为 4 部分,每部分 6 小时,这样

     06:00-11:59 | 12:00-17:59 | 18:00- 23.59 | 24:00-05:59 |
Mon| 11          | 12          | 13           | 14          | 
Tue| 21          | 22          | 23           | 24          | 
Wed| 31          | 32          | 33           | 34          | 
Thu| 41          | 42          | 43           | 44          | 
Fri| 51          | 52          | 53           | 54          | 
Sat| 61          | 62          | 63           | 64          | 
Sun| 71          | 72          | 73           | 74          | 

time_stamp 是进行观察/记录插入数据库时​​的 unix 纪元

现在我想创建一个查询,如果我为一周的开始和结束指定 time_stamp,结果是 168 行数据,给我按小时分组的呼叫总和,这样我每天得到 24 行周。这是一周内每小时的通话细分。

SUM_CALLS | Time_Slice | Hour_of_Week |
10        | 11         | 1            |  
0         | 11         | 2            | 
....
7         | 74         | 167          |  
4         | 74         | 168          |  

在上面的预期结果示例中,

    1st row is  Monday 06:00-06:59 
    2nd row is  Monday 07:00-07:59
    Last row is Sunday 04:00-05:59

【问题讨论】:

    标签: sql database sqlite group-by android-sqlite


    【解决方案1】:

    自 3.8.3 版起 SQLite 支持公用表表达式 这是一个可能的解决方案

    WITH RECURSIVE
      hours(x,y) AS (SELECT CAST(STRFTIME('%s',STRFTIME('%Y-%m-%d %H:00:00', '2014-05-05 00:00:00')) AS INTEGER),
                            CAST(STRFTIME('%s',STRFTIME('%Y-%m-%d %H:59:59', '2014-05-05 00:00:00')) AS INTEGER)
    
                UNION ALL
    
                    SELECT x+3600,y+3600 FROM hours LIMIT 168)
    
    SELECT
            COALESCE(SUM(Calls_count),0) AS SUM_CALLS,
            CASE CAST(STRFTIME('%w',x,'unixepoch') AS INTEGER)
              WHEN 0 THEN 7 ELSE STRFTIME('%w',x,'unixepoch') END
            ||
            CASE
              WHEN STRFTIME('%H:%M:%S',x,'unixepoch') BETWEEN '06:00:00' AND '11:59:59' THEN 1
              WHEN STRFTIME('%H:%M:%S',x,'unixepoch') BETWEEN '12:00:00' AND '17:59:59' THEN 2
              WHEN STRFTIME('%H:%M:%S',x,'unixepoch') BETWEEN '18:00:00' AND '23:59:59' THEN 3
              WHEN STRFTIME('%H:%M:%S',x,'unixepoch') BETWEEN '00:00:00' AND '05:59:59' THEN 4
            END AS Time_Slice,
            ((x-(SELECT MIN(x) FROM hours))/3600)+1 AS Hour_of_Week
    
      FROM hours LEFT JOIN call_logs
        ON call_logs.time_stamp >= hours.x AND call_logs.time_stamp <= hours.y
        GROUP BY Hour_of_Week
        ORDER BY Hour_of_Week
        ;
    

    这是用没有 cte 的 SQLite 版本 3.7.13 测试的:

    DROP VIEW IF EXISTS digit;
    CREATE TEMPORARY VIEW digit AS SELECT 0 AS d UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION
                                  SELECT 5      UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
                                  ;
    
    DROP VIEW IF EXISTS hours;
    CREATE TEMPORARY VIEW hours AS SELECT STRFTIME('%s','2014-05-05 00:00:00') + s AS x,
                                          STRFTIME('%s','2014-05-05 00:00:00') + s+3599  AS y
                                    FROM (SELECT (a.d || b.d || c.d) * 3600 AS s FROM digit a, digit b, digit c LIMIT 168)
                                    ;
    
    SELECT
            COALESCE(SUM(Calls_count),0) AS SUM_CALLS,
            CASE CAST(STRFTIME('%w',x,'unixepoch') AS INTEGER)
              WHEN 0 THEN 7 ELSE STRFTIME('%w',x,'unixepoch') END
            ||
            CASE
              WHEN STRFTIME('%H:%M:%S',x,'unixepoch') BETWEEN '06:00:00' AND '11:59:59' THEN 1
              WHEN STRFTIME('%H:%M:%S',x,'unixepoch') BETWEEN '12:00:00' AND '17:59:59' THEN 2
              WHEN STRFTIME('%H:%M:%S',x,'unixepoch') BETWEEN '18:00:00' AND '23:59:59' THEN 3
              WHEN STRFTIME('%H:%M:%S',x,'unixepoch') BETWEEN '00:00:00' AND '05:59:59' THEN 4
            END AS Time_Slice,
            ((x-(SELECT MIN(x) FROM hours))/3600)+1 AS Hour_of_Week
    
      FROM hours LEFT JOIN call_logs
        ON call_logs.time_stamp >= hours.x AND call_logs.time_stamp <= hours.y
        GROUP BY Hour_of_Week
        ORDER BY Hour_of_Week
        ;
    

    【讨论】:

    • 不幸的是,我无法使用我的 sqlite 数据库对此进行测试,因为它来自 Android 设备,根据Mark Carter's post,即使在其最新的操作系统版本 4.4 (Kit Kat) 中也具有 SQLite 3.7.11。有什么方法可以将我的旧 SQLite 数据库从 3.7.x 转换为 3.8.3?
    • 如果不能使用新版本的SQLite可以不用cte试试。我添加了一个新版本。
    猜你喜欢
    • 2013-02-22
    • 1970-01-01
    • 2016-07-19
    • 2017-03-15
    • 1970-01-01
    • 2016-09-13
    • 1970-01-01
    • 2011-01-22
    • 2020-07-19
    相关资源
    最近更新 更多