在Postgresql中实现类似FOR循环的功能

时间:2015-09-18 07:46:39

标签: sql postgresql for-loop

我几年来一直在干扰数据库,而且我对大多数SQL / Postgresql查询开始相当不错,但我仍然不明白如何简单的FOR-like查询应该在其中完成。这是伪代码的一个例子:

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_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中表达此查询感兴趣,因为我似乎经常需要它。

谢谢!

2 个答案:

答案 0 :(得分:4)

有几种方式,有些方式比其他方式好。

我是一般的,我主张在使用SQL和关系数据库时学习 sets 。当你将它们视为集合上的操作时,JOIN开始变得有意义。像WHEREGROUP BY这样的过滤器也是如此。您经常会发现,您可以用英语开始表达您的查询,并且只需"翻译"一段时间后,他们到SQL。 (或许我只是写道,SQL太多了,我现在已经受损了)。

具有分组和聚合的联接

在我看来,使用联接和GROUP BY是表达它的最清晰,最简单的方法。你说"这里是这两个表之间的关系,现在每个p.ids得到我最大值(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%';

此方法仅限于您只需要来自关联子表的一个字段的情况,除非您开始使用复合记录执行可怕的操作。它通常会产生与联接方法相同的查询计划,但它的灵活性较差。

它更接近" for循环"方法,因为它说'&34;对于每个父行在子表上执行此操作"。

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,所以它只在函数中有效。

它与你所写的最接近,而且在程序上思考时最简单,但它实际上是缓慢而繁琐的。

答案 1 :(得分:1)

有几种解决方案。例如,您可以使用joingroup by。在这种情况下,我最喜欢的解决方案是最直接的解决方案:

select
    id,
    (select max(timestamp) from children where parent_id=parents.id)
from parents WHERE name ilike '%something%';