【问题标题】:SELECT clause in FOR LOOP control using plpgsql使用 plpgsql 控制 FOR LOOP 中的 SELECT 子句
【发布时间】:2015-07-26 15:23:20
【问题描述】:

我尝试制作一个脚本来输出仅由一个用户使用的所有 foo,如果一个 foo 被多个用户使用,则不应输出。

这是我的桌子

foos  (id, value)
users (id, name)
used  (foo_id, user_id)

我的脚本不工作

FUNCTION output_unshared_foos ()
RETURNS foos AS
$a$
DECLARE
  foocounts RECORD;
BEGIN
  SELECT u.foo_id, count(*)
  INTO foocounts -- store in the local variable
  FROM used u
  GROUP BY u.foo_id;

  FOR f IN SELECT * FROM foos
  LOOP
    IF (SELECT fc.count < 2 FROM foocounts fc WHERE fc.foo_id = f.id) THEN
      RETURN NEXT f;
    END IF;
  END LOOP;
END
$a$ language plpgsql;

似乎不起作用,返回每一行,条件控制似乎总是为真。

【问题讨论】:

  • 手工制作的表定义远不如你在 psql 中使用 \d tbl 得到的有用。而且您忘记声明您的 Postgres 版本。此外,您呈现的内容在语法上是无效的,并且会产生错误消息,而不是结果。

标签: postgresql select for-loop plpgsql


【解决方案1】:

您的第一个问题是您无法将返回多行的查询结果存储到单个变量中(SELECT u.foo_id, count(*) INTO ... 部分)。我很惊讶您在调用函数时没有收到运行时错误。

您的函数也无法编译,因为记录 f 未声明且定义为 returns foos 的函数无法使用 return next

但是你的方法是错误的(即使它有效)。在 SQL 中进行逐行处理几乎总是错误的选择。 SQL 和关系数据库旨在处理集合,而不是单行。

您的问题可以通过一个查询来解决:

select foo_id
from used
group by foo_id
having count(distinct user_id) = 1

将返回仅由一个用户使用的所有 foo id。

如果您需要foos 表中的其他信息,可以将上述查询加入到 foos 表中:

select f.*
from foos f
  join (
     select foo_id
     from used
     group by foo_id
     having count(distinct user_id) = 1
  ) u on f.id = u.foo_id

【讨论】:

  • 谢谢,但我应该提到我正在使用一个函数,因为在returning next f 之前我需要在我的表中进行一些处理..
  • @발렌텐:在提问时,您应该始终说明您的完整要求。但这听起来好像你只需要在我的第二个查询中添加一个 where 子句
  • @발렌텐:另外,你总是可以遍历我的第二个查询的结果。您仍然会进行缓慢的逐行处理,但它会比您的解决方案更快。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-26
  • 2018-08-22
  • 1970-01-01
  • 1970-01-01
  • 2017-03-11
  • 2016-07-05
  • 1970-01-01
相关资源
最近更新 更多