聚合 SQL 中缺少布尔值的行

Aggregating rows in SQL with missing Booleans

我有下面的 SQL 脚本,其中 returns 来自 PostgreSQL 数据库视图 table 的以下数据。

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、速度、温度、距离的最新读数。 对于高速和高温布尔值,我想要最新可用的布尔值,如果没有可用的布尔值,我想要一个空单元格。

预期输出

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

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

谢谢。

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

相反,让我们去 ROW_NUMBER() 获取最近的行。并且 fiddle 使用数组获取最新的布尔值:

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;

您可以使用 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