4

考虑 PostgreSQL 9.4 中的以下事件数据:

      eventTime     | eventName
2015-09-25 18:00:00 | 'AAA'
2015-09-25 17:00:00 | 'BBB'
2015-09-25 16:00:00 | 'BBB'
2015-09-25 15:00:00 | 'BBB'
2015-09-25 14:00:00 | 'AAA'
2015-09-26 13:00:00 | 'CCC'
2015-09-26 12:00:00 | 'AAA'
2015-09-26 11:00:00 | 'BBB'
2015-09-26 10:00:00 | 'CCC'
2015-09-26 09:00:00 | 'BBB'
2015-09-27 08:00:00 | 'AAA'
2015-09-27 07:00:00 | 'CCC'
2015-09-27 05:00:00 | 'CCC'
2015-09-27 04:00:00 | 'CCC'
2015-09-27 03:00:00 | 'CCC'
2015-09-27 02:00:00 | 'AAA'

虽然基于单一count()的表很简单,例如:

SELECT eventTime, count(1)
  from (SELECT data->>'eventName' as eventName,
        date_trunc('day', to_timestamp(data->>'timestamp','YYYY-MM-DDZHH24:MI:SS.MS')::timestamp without time zone) AS eventTime
        FROM sidetrack where (data->>'eventName' = 'AAA') IS TRUE) AS tmptab
GROUP BY eventTime
ORDER BY eventTime ASC

只能计算 的单个值的出现次数eventName。我对 SQL 不是很有经验,并且正在努力寻找一种方法来创建双向频率表。在此示例中,结果将是:

     day    | 'AAA' | 'BBB' | 'CCC'
------------+-------+-------+-------
 2015-09-25 |    2  |    3  |    0
 2015-09-26 |    1  |    2  |    2
 2015-09-27 |    2  |    0  |    4

有些示例使用 对具有数值的变量进行计数with_bucket(),但这并不适用于字符串值字段。

我尝试过嵌套选择WITH,例如:

WITH
    foo AS (
        SELECT ...
    ),
    bar AS (
        SELECT ...
    FROM foo
    ),
SELECT *
FROM bar;

和外部连接,但我无法破解这个。

4

2 回答 2

1

您可以只为每列使用 CASE 语句为匹配生成 1,然后对所有行求和,例如;

SELECT date_trunc('day', timestamp) AS time,
       SUM(CASE WHEN "eventName" = 'AAA' THEN 1 ELSE 0 END) AAA,
       SUM(CASE WHEN "eventName" = 'BBB' THEN 1 ELSE 0 END) BBB,
       SUM(CASE WHEN "eventName" = 'CCC' THEN 1 ELSE 0 END) CCC
FROM sidetrack
GROUP BY date_trunc('day', timestamp)
ORDER BY date_trunc('day', timestamp) ASC

一个用于测试的 SQLfiddle。

于 2015-12-19T23:13:49.000 回答
1

此查询选择每天的事件计数:

select day, event, count(*)
from (
    select 
        left(date_trunc('day', (data->>'timestamp')::timestamp)::text, 10) as day, 
        data->>'eventName' as event
    from sidetrack
    ) s
group by 1, 2
order by 1 asc, 2;

    day     | event | count 
------------+-------+-------
 2015-09-25 | AAA   |     2
 2015-09-25 | BBB   |     3
 2015-09-26 | AAA   |     1
 2015-09-26 | BBB   |     2
 2015-09-26 | CCC   |     2
 2015-09-27 | AAA   |     2
 2015-09-27 | CCC   |     4
(7 rows)

crosstab()您可以在函数中使用查询:

create extension if not exists tablefunc;

select * from crosstab (
    $q$
        select day, event, count(*)
        from (
            select 
                left(date_trunc('day', (data->>'timestamp')::timestamp)::text, 10) as day, 
                data->>'eventName' as event
            from sidetrack
            ) s
        group by 1, 2
        order by 1 asc
    $q$,
    $q$
        values ('AAA'), ('BBB'), ('CCC')
    $q$)
as ct (day text, "AAA" int, "BBB" int, "CCC" int);

    day     | AAA | BBB | CCC 
------------+-----+-----+-----
 2015-09-25 |   2 |   3 |    
 2015-09-26 |   1 |   2 |   2
 2015-09-27 |   2 |     |   4
(3 rows)
于 2015-12-19T23:24:26.030 回答