【问题标题】:SQL query based on time series data基于时序数据的SQL查询
【发布时间】:2021-07-15 13:42:22
【问题描述】:

我有 2 个如下表:

create table parent_child
(
    parent_id int not null,
    child_id int not null
    
);

INSERT INTO parent_child (parent_id, child_id) VALUES (117722, 273215);
INSERT INTO parent_child (parent_id, child_id) VALUES (117722, 117936);
INSERT INTO parent_child (parent_id, child_id) VALUES (117722, 117873);
INSERT INTO parent_child (parent_id, child_id) VALUES (117722, 123305);

INSERT INTO parent_child (parent_id, child_id) VALUES (104151, 240006);
INSERT INTO parent_child (parent_id, child_id) VALUES (104151, 240005);
INSERT INTO parent_child (parent_id, child_id) VALUES (104151, 239415);
INSERT INTO parent_child (parent_id, child_id) VALUES (104151, 239414);

INSERT INTO parent_child (parent_id, child_id) VALUES (5316, 118310);
INSERT INTO parent_child (parent_id, child_id) VALUES (5316, 130627);
INSERT INTO parent_child (parent_id, child_id) VALUES (5316, 298564);
INSERT INTO parent_child (parent_id, child_id) VALUES (5316, 118311);
INSERT INTO parent_child (parent_id, child_id) VALUES (5316, 118312);
create table child
(
    child_id int not null,
    tstamp datetime not null,
    value float,
);

-- Parent 117722
INSERT INTO child (child_id, tstamp, value) VALUES (273215, '2021-07-14 00:00:00.000000',  29);
INSERT INTO child (child_id, tstamp, value) VALUES (117936, '2021-07-14 00:00:00.000000',  52);
INSERT INTO child (child_id, tstamp, value) VALUES (117873, '2021-07-14 00:00:00.000000',  51);
INSERT INTO child (child_id, tstamp, value) VALUES (123305, '2021-07-14 00:00:00.000000',  31);

-- Parent 104151
INSERT INTO child (child_id, tstamp, value) VALUES (240006, '2021-07-14 00:00:00.000000',  37);
INSERT INTO child (child_id, tstamp, value) VALUES (240005, '2021-07-14 00:00:00.000000',  88);
INSERT INTO child (child_id, tstamp, value) VALUES (239415, '2021-07-14 00:00:00.000000',  29);
INSERT INTO child (child_id, tstamp, value) VALUES (239414, '2021-07-14 00:00:00.000000',  19);

-- Parent 5316
INSERT INTO child (child_id, tstamp, value) VALUES (118310, '2021-07-14 00:00:00.000000',  42);
INSERT INTO child (child_id, tstamp, value) VALUES (130627, '2021-07-14 00:00:00.000000',  11);
INSERT INTO child (child_id, tstamp, value) VALUES (298564, '2021-07-14 00:00:00.000000',  36);
INSERT INTO child (child_id, tstamp, value) VALUES (118311, '2021-07-14 00:00:00.000000',  22);
INSERT INTO child (child_id, tstamp, value) VALUES (118312, '2021-07-14 00:00:00.000000',   9);

-- Parent 117722
INSERT INTO child (child_id, tstamp, value) VALUES (273215, '2021-07-14 00:05:00.000000',  72);
INSERT INTO child (child_id, tstamp, value) VALUES (117936, '2021-07-14 00:05:00.000000',  99);
INSERT INTO child (child_id, tstamp, value) VALUES (117873, '2021-07-14 00:05:00.000000',  13);
INSERT INTO child (child_id, tstamp, value) VALUES (123305, '2021-07-14 00:05:00.000000',  24);

-- Parent 104151
INSERT INTO child (child_id, tstamp, value) VALUES (240006, '2021-07-14 00:05:00.000000',  65);
INSERT INTO child (child_id, tstamp, value) VALUES (240005, '2021-07-14 00:05:00.000000',  63);
INSERT INTO child (child_id, tstamp, value) VALUES (239415, '2021-07-14 00:05:00.000000',  23);
INSERT INTO child (child_id, tstamp, value) VALUES (239414, '2021-07-14 00:05:00.000000',  15);

-- Parent 5316
INSERT INTO child (child_id, tstamp, value) VALUES (118310, '2021-07-14 00:05:00.000000',  19);
INSERT INTO child (child_id, tstamp, value) VALUES (130627, '2021-07-14 00:05:00.000000',  22);
INSERT INTO child (child_id, tstamp, value) VALUES (298564, '2021-07-14 00:05:00.000000',  47);
INSERT INTO child (child_id, tstamp, value) VALUES (118311, '2021-07-14 00:05:00.000000',  54);
INSERT INTO child (child_id, tstamp, value) VALUES (118312, '2021-07-14 00:05:00.000000',  12);

子表中的数据每 5 分钟重复一次。也就是说,对于父母的每个孩子,将有 288 个数据点。这将进一步重复每一天,在一个数据点使用不同(或相同)的值。

问题:

(1) 找出parent_iddate_when_count_of_value_above_30_more_than_12_times_in_a_daycount_of_values_above_30_each_day,其中父母的所有孩子的值超过 30,每天超过 12 次,每周至少 3 天。数据点不必是连续的。换句话说,如果在某个数据点(例如 2021-07-14 00:00:00.000000)的父级的所有子级中的 MAX(value) 高于 30,那么这将被视为该父级在该日期发生的一次.

(2) 找出parent_idlatest_datetime_in_the_weekmax_value_across_all_children_in_a_week,其中父级所有子级的value 最大,以及最大的日期时间。如果多个日期时间具有相同的最大值,则选择最新的日期时间。

如果这两个查询可以组合在一个查询中,那就是我想要的。否则,这些可能是 2 个不同的查询。如果是单个查询,则问题 (2) 的输出将针对问题 (1) 的每一行重复,这是可以接受的。

输入:

parent_ids 的列表,例如 WHERE parent_id IN (117722, 5316)

示例输出(如果 2 个查询合二为一;列名可以是任何内容,为简洁起见,我将使用长名称):

parent_id | date_when_count_of_value_above_30_more_than_12_times_in_a_day | count_of_values_above_30_each_day | max_value_across_all_children_in_a_week | latest_datetime_in_the_week
117722    | 2021-07-14                                                    | 13                                | 99                                      | 2021-07-09 16:15:00.000000
117722    | 2021-07-11                                                    | 28                                | 99                                      | 2021-07-09 16:15:00.000000
104151    | 2021-07-14                                                    | 19                                | 65                                      | 2021-07-11 18:30:00.000000
104151    | 2021-07-13                                                    | 27                                | 65                                      | 2021-07-11 18:30:00.000000
104151    | 2021-07-11                                                    | 36                                | 65                                      | 2021-07-11 18:30:00.000000

以上只是一个示例输出。当然,如果一周内出现的次数不超过 3,则 parent_id 不会出现在输出中。

【问题讨论】:

  • 请用版本标记您的数据库管理系统。
  • 你能解释一下288个数据点的数字吗?
  • 好的.. 24*12 知道了
  • 24 小时 = 1440 分钟。因此,如果数据每 5 分钟出现在表格中,那么每个孩子每天有 288 个条目
  • 你能分享value的可能差异吗?它变化的速度有多快,变化的幅度有多大,是否有“柔和的曲线”或峰值?我可以将 Vertica TIMESERIES 子句与 RANDOM()RANDOMINT() 函数一起使用,以每天生成 288 个均匀分布的子行,并通过几行代码生成子标识符。我可以只使用定义范围内的随机数吗?

标签: sql vertica


【解决方案1】:

三个选择,全部取决于父 ID。并使用 Vertica 的解析限制子句:LIMIT 1 OVER()

WITH
w_p AS (
  SELECT
    parent_id
  , child.*
  FROM parent_child
  JOIN child USING(child_id)
)
,
o_30_count AS (
  SELECT
    parent_id
  , tstamp::DATE
  , SUM(CASE WHEN val > 30 THEN 1 END) AS over_30_count
  FROM w_p 
  GROUP BY 1,2 
  HAVING over_30_count > 12
)
,
max_per_week AS (
  SELECT
    parent_id
  , WEEK(tstamp)
  , MAX(val) AS max_per_week
  FROM w_p
  GROUP BY 1,2
  LIMIT 1 OVER(PARTITION BY parent_id ORDER BY max_per_week DESC)
)
,
last_max_per_week AS (
  SELECT
    parent_id
  , tstamp AS last_week_ts
  FROM w_p
  LIMIT 1 OVER(PARTITION BY parent_id,WEEK(tstamp) ORDER BY val DESC)
)
SELECT
  o_30_count.parent_id
, over_30_count
, max_per_week
, last_week_ts
FROM o_30_count 
JOIN max_per_week USING(parent_id)
JOIN last_max_per_week USING(parent_id);

【讨论】:

  • 感谢您的回复。如果您可以帮助澄清 wrt Vertica Analytic Database v9.1.1-5,有几个问题。 (1) 此版本不支持LIMIT 1 OVER()。有解决方法吗? (2)HAVING子句中不能使用列别名over_30_count。所以,我想我可以使用HAVING SUM(CASE WHEN val > 30 THEN 1 END)。再次感谢您的帮助。
  • 分析限制子句LIMIT (n) OVER(PARTITION BY (column_list) ORDER BY (column_list) ) 已经存在多年了。再试一次...
  • 我明白了:AT、FOR、ISNULL、NOTNULL、OFFSET、TIME、WITH 或 '[' 预期,得到 'OVER'
  • 这不是典型的 Vertica 错误消息。 Vertica 会说:ERROR 4856: Syntax error at or near "OVER" at character 176。所以这是一个不同的SQL数据库的错误信息。
  • 你是对的。我正在从 IntelliJ IDEA 运行 Vertica 查询,似乎选择的方言有问题。一切都按预期工作。感谢您抽出宝贵时间解决此问题。
【解决方案2】:

我在 Sybase 中对此进行了测试。您可以利用该逻辑并将 Vertica 转换为特定的。此外,对于一周,我从时间戳中获取一周中的年份。您可以根据您的要求对其进行修改。比如今天 -7 天或基于窗口。

(1)

Select * from
(Select
p.parent_id                     as 'parent_id',
convert(varchar, c.tstamp, 101) as 'date_when_count_of_value_above_30_more_than_12_times_in_a_day',
count(*)                        as 'count_of_values_above_30_each_day '
from #parent_child p LEFT OUTER JOIN #child c
on p.child_id = c.child_id
where 
c.value > 30 and
p.parent_id in (5316, 117722, 104151)
group by 
convert(varchar, c.tstamp, 101), p.parent_id
having count(*) > 12) tb1
group by datepart(cwk, tb1.date_when_count_of_value_above_30_more_than_12_times_in_a_day), parent_id
having count(*) >=3

(2)

Select
parent_id      as 'parent_id',
MAX(tstamp)    as 'latest_datetime_in_the_week',
value          as 'max_value_across_all_children_in_a_week' 
from 
(Select
p.parent_id,c.tstamp,c.value from #parent_child p LEFT OUTER JOIN #child c
on p.child_id = c.child_id
JOIN 
(Select
MAX(c.value) as 'max_value'
from #parent_child p LEFT OUTER JOIN #child c
on p.child_id = c.child_id
where
datepart(cwk, tstamp) = 28
group by 
datepart(cwk, tstamp), p.parent_id) tbl1
ON c.value = tbl1.max_value) tbl2
group by parent_id, value

【讨论】:

    【解决方案3】:

    对于(1):

    注意:为了便于阅读,我将 parentId 移到子表中

    WITH BYDAY AS
    (
        SELECT COUNT(*) as CountHiValsOnDay, parent_id, CAST(tstamp as date) as tsDate, DATEPART(week, CAST(tstamp as date)) as TheWeek, YEAR(CAST(tstamp as date)) as TheYear
        FROM child
        WHERE value > 30
        GROUP BY parent_id, CAST(tstamp as date)
        HAVING COUNT(*) > 12
    )
    SELECT
        bd1.parent_id,
        bd1.tsDate,
        bd1.CountHiValsOnDay,
        bd2.CountThisWeek
    FROM BYDAY bd1
        JOIN (
            SELECT COUNT(*) as CountThisWeek, jj.parent_id, jj.TheWeek, jj.TheYear
            FROM BYDAY jj
            GROUP BY jj.parent_id, jj.TheWeek, jj.TheYear
        ) bd2
          ON bd2.parent_id = bd1.parent_id AND
              bd2.TheWeek = bd1.TheWeek AND
              bd2.TheYear = bd1.TheYear
    WHERE bd2.CountThisWeek >= 3
    

    【讨论】:

    • 谢谢你,尼尔。我回来后会试试这个。但是,我只专注于按 tstamp 分组,这让我很头疼。我相信你所展示的会奏效。您打破了 tstamp,提取了日期部分并对其进行了分组。再次感谢。一旦我尝试了,我会反馈。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多