我已经接触数据库几年了,我开始能够很好地处理大多数 SQL/Postgresql 查询,但我仍然不明白应该如何在其中完成一个简单的类似 FOR 的查询.这是一个伪代码示例:
FOR id IN SELECT ids FROM parents WHERE name ilike '%something%' LOOP
SELECT parent_id, max(timestamp) FROM children WHERE parent_id = id;
END LOOP;
注意:一位 parent 可以有并且经常有多个 child ,因此他们之间存在一对多关系。
该查询的预期结果应该是这样的:
parent_id, max(timestamp)
5, 2015-09-18 10:00:46.684824+03
6, 2015-09-18 10:00:47.684824+03
8, 2015-09-18 10:00:48.684824+03
etc.
查询本身不必是 for 循环。我只是对如何用 SQL 表达这个查询感兴趣,因为我似乎经常需要它。
谢谢!
最佳答案
有几种方法,有些比其他的好。
总的来说,我提倡在使用 SQL 和关系数据库时学习集合 思考。当您将 JOIN
视为对集合的操作时,它们开始变得很有意义。 WHERE
和 GROUP BY
等过滤器也是如此。您经常会发现您可以开始用英语表达您的查询,并在一段时间后将它们“翻译”成 SQL。 (或者也许我只是写了太多的 SQL,现在我已经损坏了)。
带分组和聚合的连接
在我看来,使用连接和 GROUP BY
是最清晰和最简单的表达方式。你说“这是这两个表之间的关系,现在为每个 p.ids 得到 max(c.timestamp)”。
SELECT
p.ids,
max(c.timestamp)
FROM parents
LEFT OUTER JOIN children c ON (p.ids = c.parent_id)
WHERE p.name ILIKE '%something%'
GROUP BY p.ids;
我使用了 LEFT OUTER JOIN
,因为在简单的 FOR
循环中,您会得到一个带有 parent_id 和 null max
的结果如果没有匹配的行。这保留了相同的行为。如果在没有子行的情况下根本不想要任何行,请使用 inner join
。
相关子查询
SELECT
p.ids,
(SELECT max(timestamp) FROM children c WHERE c.parent_id = p.ids)
FROM parents
WHERE p.name ILIKE '%something%';
这种方法仅限于您只需要关联子表中的一个字段的情况,除非您开始使用复合记录做一些可怕的事情。它通常会产生与连接方法相同的查询计划,但灵 active 较低。
它更接近于“for 循环”方法,因为它说“对每个父行在子表上执行此操作”。
PL/PgSQL 中的FOR
循环
这是最慢且笨拙的,但几乎就是您所写的内容。
FOR id IN SELECT ids FROM parents WHERE name ilike '%something%' LOOP
RETURN QUERY SELECT parent_id, max(timestamp) FROM children WHERE parent_id = id;
END LOOP;
是的,我几乎一字不差地复制了您的代码。它看起来像完全有效的 PL/PgSQL,只是没有结果的目的地。在上面的表格中,您需要声明过程 RETURNS TABLE(...)
。
最后一个是 PL/PgSQL,所以它只在函数中有效。
它最接近你写的东西,在程序上思考时也是最简单的,但实际上又慢又麻烦。
关于sql - 在 Postgresql 中实现类似 FOR 循环的功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32646580/