我几年来一直在干扰数据库,而且我对大多数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中表达此查询感兴趣,因为我似乎经常需要它。
谢谢!
答案 0 :(得分:4)
有几种方式,有些方式比其他方式好。
我是一般的,我主张在使用SQL和关系数据库时学习 sets 。当你将它们视为集合上的操作时,JOIN
开始变得有意义。像WHERE
和GROUP 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;对于每个父行在子表上执行此操作"。
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)
有几种解决方案。例如,您可以使用join
和group by
。在这种情况下,我最喜欢的解决方案是最直接的解决方案:
select
id,
(select max(timestamp) from children where parent_id=parents.id)
from parents WHERE name ilike '%something%';