这是一个我一直绞尽脑汁的问题。假设我有一个表,其中包含一系列时间戳和一个部件号作为主键。该表存储增量更改,这意味着对于每个时间戳,如果字段更改,则记录该更改。如果该字段未更改,则对于新时间戳,它为NULL。 这是基本的想法。
part | timestamp | x-pos | y-pos | status
------+-----------+-------+-------+--------
a5 | 151 | 5 | 15 | g
a5 | 153 | NULL | 17 | NULL
(part, timestamp)
是主键。第二条记录中的NULL
表示自第一条记录以来未更改的值。
我希望能够选择按部件分组的每个字段的最新值。例如,给定上述条目,对于部分a5,结果将为153,5,17,g。
到目前为止,我已将此黑客一起查询。
((SELECT x-pos FROM part_changes WHERE x-pos IS NOT NULL
ORDER BY timestamp DESC
LIMIT 1)
UNION
(SELECT y-pos FROM part_changesWHERE y-pos IS NOT NULL
ORDER BY timestamp DESC
LIMIT 1)
UNION
(SELECT status FROM part_changes WHERE status IS NOT NULL
ORDER BY timestamp DESC
LIMIT 1))
但这会返回一个列,这意味着我可以使用group-by进行组织。
必须有更优雅的做事方式,例如以创造性的方式使用COALESCE或IS NULL。但是我被困住了,无法弄明白。有人有个主意吗?
不,我无法改变数据库结构。
编辑:鲁赫克有正确的想法。现在唯一的问题是按部分分组。我似乎无法通过多个部分绕过LIMIT 1
进行分组。有任何想法吗?
mdahlman,我对postgresql中的分析函数不太熟悉。因此,如果该解决方案比复杂查询更容易,那么请务必发布您的想法。
编辑2:谢谢大家的帮助。我想我已经掌握了我需要做的事情。
答案 0 :(得分:5)
而不是使用UNION
,听起来你真的想要字段列表中的子查询。也就是说,您需要(SELECT ...) UNION (SELECT ...) UNION (SELECT ...)
而不是SELECT (SELECT ...), (SELECT ...), (SELECT ...)
。
例如:
SELECT part,
( SELECT x_pos
FROM part_changes
WHERE part = pc.part
AND x_pos IS NOT NULL
ORDER
BY timestamp DESC
LIMIT 1
) AS x_pos,
( SELECT y_pos
FROM part_changes
WHERE part = pc.part
AND y_pos IS NOT NULL
ORDER
BY timestamp DESC
LIMIT 1
) AS y_pos,
( SELECT status
FROM part_changes
WHERE part = pc.part
AND status IS NOT NULL
ORDER
BY timestamp DESC
LIMIT 1
) AS status
FROM ( SELECT DISTINCT
part
FROM part_changes
) AS pc
;
但是在这一点上我真的会考虑编写一个存储过程。
可替换地:
SELECT DISTINCT
part,
FIRST_VALUE(x_pos) OVER
( PARTITION BY part
ORDER BY CASE WHEN x_pos IS NULL
THEN NULL
ELSE TIMESTAMP
END DESC NULLS LAST
) AS x_pos,
FIRST_VALUE(y_pos) OVER
( PARTITION BY part
ORDER BY CASE WHEN y_pos IS NULL
THEN NULL
ELSE TIMESTAMP
END DESC NULLS LAST
) AS y_pos,
FIRST_VALUE(status) OVER
( PARTITION BY part
ORDER BY CASE WHEN status IS NULL
THEN NULL
ELSE TIMESTAMP
END DESC NULLS LAST
) AS status
FROM part_changes
;
答案 1 :(得分:2)
只有一个部分,这应该给你答案..感谢 ruakh
但我不喜欢这个版本..
SELECT
(SELECT timestamp FROM part_changes WHERE part = $part
ORDER BY timestamp DESC
LIMIT 1) as timestamp,
(SELECT x-pos FROM part_changes WHERE part = $part and x-pos IS NOT NULL
ORDER BY timestamp DESC
LIMIT 1) as xpos,
(SELECT y-pos FROM part_changes WHERE part = $part and y-pos IS NOT NULL
ORDER BY timestamp DESC
LIMIT 1) as ypos,
(SELECT status FROM part_changes WHERE part = $part and status IS NOT NULL
ORDER BY timestamp DESC
LIMIT 1)) as status
答案 2 :(得分:1)
相关时间戳列表:
select max timestamp from part_changes where x_POS is not null group by part
您可以将其设为视图:让我们调用此view1
SELECT part_changes.part, part_changes.x-pos
FROM part_changes left join view1 on part_changes.part = view1.part
WHERE x-pos IS NOT NULL
AND part_changes.timestamp = view1.timestamp
GROUP BY part_changes.part
看看我要去哪里?这应该为您提供x-pos的完整列表。
答案 3 :(得分:0)
您也可以在应用程序中执行此操作。使您的程序按批次顺序请求行,例如10行。如上所述聚合这些批次。如果在当前批次完成后,空列就会获得下一批。