【问题标题】:Aggregating rows in SQL with missing Booleans在 SQL 中聚合缺少布尔值的行
【发布时间】:2021-06-18 16:35:24
【问题描述】:

我有以下 SQL 脚本,它从 PostgreSQL 数据库视图表中返回以下数据。

SELECT 
  "V_data".macaddr,
  "V_data".sensorid,
  "V_data".ts,
  "V_data".velocity,
  "V_data".temp,
  "V_data".highspeed,
  "V_data".hightemp,
  "V_data".distance,

FROM 
  sensordb."V_data"

WHERE 
  "V_data".macaddr like '%abcdef'

AND
  (
  ("V_data".sensorid = 'abc1') or ("V_data".sensorid = 'a2bc') or ("V_data".sensorid = 'ab3c') 
  )

AND
  "V_data".ts >= 1616370867000

ORDER BY
  "V_data".ts DESC;

输出

macaddr sensorid ts velocity temp highspeed hightemp distance
abcdef abc1 1616370867010 25 32 52
abcdef a2bc 1616370867008 27 35 T 51
abcdef ab3c 1616370867006 26 30 50
abcdef abc1 1616370867005 24 36 T 50
abcdef a2bc 1616370867004 27 31 50
abcdef abc1 1616370867002 21 30 T 48
abcdef ab3c 1616370867000 22 33 F 46

我想聚合这些行,以便获得每个传感器 ts、速度、温度、距离的最新读数。 对于布尔值 h​​ighspeed 和 hightemp,如果没有可用的布尔值,我想要最新的可用布尔值或空单元格。

预期输出

macaddr sensorid ts velocity temp highspeed hightemp distance
abcdef abc1 1616370867010 25 32 T T 52
abcdef a2bc 1616370867008 27 35 T 51
abcdef ab3c 1616370867006 26 30 F 50

我怎样才能简化这个任务?

谢谢。

【问题讨论】:

    标签: sql postgresql aggregate-functions


    【解决方案1】:

    您可以使用DISTINCT ON(仅在 PostgreSQL afaik 中可用)来简化此查询。你可以这样做:

    with
    q as (
      -- your query here
    )
    select 
      l.macaddr, l.sensorid, l.ts, l.velocity, l.temp,
      s.highspeed, t.hightemp, 
      l.distance  
    from (
      select distinct on (sensorid) *
      from q
      order by sensorid, ts desc
    ) l
    left join (
      select distinct on (sensorid) *
      from q
      where highspeed is not null
      order by sensorid, ts desc
    ) s on s.sensorid = l.sensorid
    left join (
      select distinct on (sensorid) *
      from q
      where hightemp is not null
      order by sensorid, ts desc
    ) t on t.sensorid = l.sensorid
    

    【讨论】:

    • 非常感谢。你的代码就像一个魅力。
    【解决方案2】:

    嗯。 . .对于除布尔列 DISTINCT ON 之外的所有列都可以使用。但是这些布尔值很棘手。您可以对布尔值使用一些技巧。

    相反,让我们使用ROW_NUMBER() 来获取最新的行。并摆弄数组以获取最新的布尔值:

    SELECT d.macaddr, d.sensorid,
           MAX(d.ts) as ts,
           MAX(d.velocity) FILTER (WHERE seqnum = 1) as velocity,
           MAX(d.temp) FILTER (WHERE seqnum = 1) as temp,
           (ARRAY_REMOVE(ARRAY_AGG(d.highspeed ORDER BY ts DESC), NULL))[1] as highspeed,
           (ARRAY_REMOVE(ARRAY_AGG(d.hightemp ORDER BY ts DESC), NULL))[1] as hightemp
           MAX(d.distance) FILTER (WHERE seqnum = 1)
    FROM (SELECT d.*,
                 ROW_NUMBER() OVER (PARTITION BY d.macaddr, d.sensorid ORDER BY ts DESC) as seqnum
          FROM sensordb."V_data" d
          WHERE d.macaddr like '%abcdef' AND
                d.sensorid IN ('abc1', 'a2bc', 'ab3c') AND
                d.ts >= 1616370867000
         ) d
    GROUP BY d.macaddr, d.sensorid
    ORDER BY d.ts DESC;
    

    【讨论】:

    • 感谢您的建议。对您的代码稍作修改,我就能得到结果。您还给了我一个新的视角来使用 ROW_NUMBER 来看待它。
    • @aj7amigo 。 . .与使用多个JOINs 相比,它的性能如何。出于性能原因,我试图避免加入。
    • 目前,数据库中的行数非常少(低于 1000 行)。所以我看不出执行时间有什么不同。您和@The Impaler 的代码可以在 1 秒内运行。但随着数据随着时间的推移而增长,我会密切关注它。非常感谢您的提示。干杯。
    猜你喜欢
    • 2020-01-05
    • 2023-01-29
    • 1970-01-01
    • 2019-12-10
    • 2022-08-03
    • 2010-10-30
    • 2014-03-09
    • 2020-07-05
    • 1970-01-01
    相关资源
    最近更新 更多