【问题标题】:SQL select statement yielding same results as PL/pgSQL FOR loopSQL select 语句产生与 PL/pgSQL FOR 循环相同的结果
【发布时间】:2019-05-01 20:16:05
【问题描述】:

我很难理解何时使用 PL/pgSQL FOR 循环与常规 SQL。

这个问题绝对是在显示我的幼稚,但这是我感到困惑的地方:

给定这张表:

CREATE TABLE bins  AS 
SELECT * FROM GENERATE_SERIES(1, 10) AS id;

如果我想在每一行的 id 字段中加 1,我会这样做:

select id+1 from bins;

会正确返回

2
3
4
5
6
7
8
9
10
11

现在,如果我为此操作使用 PL/pgSQL 函数,它看起来像这样:

CREATE OR REPLACE FUNCTION add_one(
n integer
) 
RETURNS VOID AS $$
DECLARE
    rec RECORD;
BEGIN
    FOR rec IN SELECT id
        FROM bins
    LOOP 
 RAISE NOTICE '%', rec.id+n;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

那么

select add_one(1)

会产生

-- Executing query:
select add_one(1)
NOTICE:  2
CONTEXT:  PL/pgSQL function add_one(integer) line 9 at RAISE
NOTICE:  3
CONTEXT:  PL/pgSQL function add_one(integer) line 9 at RAISE
NOTICE:  4
CONTEXT:  PL/pgSQL function add_one(integer) line 9 at RAISE
NOTICE:  5
CONTEXT:  PL/pgSQL function add_one(integer) line 9 at RAISE
NOTICE:  6
CONTEXT:  PL/pgSQL function add_one(integer) line 9 at RAISE
NOTICE:  7
CONTEXT:  PL/pgSQL function add_one(integer) line 9 at RAISE
NOTICE:  8
CONTEXT:  PL/pgSQL function add_one(integer) line 9 at RAISE
NOTICE:  9
CONTEXT:  PL/pgSQL function add_one(integer) line 9 at RAISE
NOTICE:  10
CONTEXT:  PL/pgSQL function add_one(integer) line 9 at RAISE
NOTICE:  11
CONTEXT:  PL/pgSQL function add_one(integer) line 9 at RAISE

所以我的问题是,SQL select 语句在某种程度上就像一个 for 循环,因为在这个例子中,它为每一行添加一个 1……这与 PL/pgSQL 函数中发生的事情相同。这是一个准确的描述吗?

【问题讨论】:

  • 您的最终比较是准确的。这也有点无意义。斧头能劈木头,炸弹也能劈。这告诉我们什么?真的没什么。简单的SELECT 比在 plpgsql 中循环更快、更简单、更短且更不容易出错。就是这样。
  • 与其指出循环和SQL语句可以用来做一些相同的事情,更重要的是要注意它们可以用来做不同的事情。例如,如果您需要构建和执行一系列 SQL 语句,这些语句的选择标准(将在 WHERE 子句中使用)存储在表的行中,那么循环遍历表的行将很有用,而没有一个SQL 语句将创建并执行整个 SQL 语句系列。

标签: sql postgresql plpgsql


【解决方案1】:

你的描述是准确的。

此时您最大的问题可能是理解 SQL 的非过程性质。在这种语言中,您无需指定达到结果所需的步骤,您只需描述您想要的结果。

因此,对于表中的每一行,您想要id 的 SQL 语句都加一。如果数据库通过在内部运行循环或出于上帝的行为来做到这一点,则不是您的主要关注点。

一开始这对许多过程程序员来说很奇怪,但是一旦你习惯了它就会让生活变得更好:你不必了解所有的数据库内部结构来找出处理查询的最佳方法。 优化器会为你做这件事,而且通常比你自己做的要好。

当然,想知道查询是如何在内部处理的,这是一种健康的好奇心。为此,您使用EXPLAIN 语句。这对于分析和修复性能问题尤其必要。

经验法则是,在一个更大的 SQL 语句中执行尽可能多的工作通常比在与应用程序代码捆绑在一起的许多简单的小语句中更好。这是因为这种方式的开销更少,还因为更大的语句通常会为优化器打开更多的方法。例如,嵌套循环是最简单的,但并不总是解决问题的最佳方法。

【讨论】:

  • 我已经使用 SQL 几年了,您描述其使用心态的方式“在这种语言中,您没有指定达到结果所需的步骤,您只描述了您想要的结果”这就是我一直在接近 SQL 的方式。我问这个问题的原因是因为我最近遇到了一个非常复杂的任务,我无法在 SQL 中解决(子查询、CTE'S、横向没有用),我不得不使用 pgsql for 循环来解决这个问题。我仍然不清楚为什么我的代码需要一个 for 循环。但它有效。所以正如你所说,它只是健康的好奇心 - 感谢您的说明
  • 循环是必需的,因为 PL/pgSQL 是一种过程语言(这就是“PL”的含义)。在过程代码中处理结果集的方式是循环它们。当然,同样的事情发生在数据库中,只是效率更高,而你看不到。
  • 当然没错...我的意思是我不清楚为什么我不能使用纯 SQL 来产生我想要的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-05
  • 2019-08-31
相关资源
最近更新 更多