SQL select语句产生与PL / pgSQL FOR循环相同的结果

时间:2019-05-01 20:16:05

标签: sql postgresql plpgsql

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

这个问题肯定显示出我的天真,但这是我感到困惑的地方:

给出此表:

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函数中发生的情况相同。这是一个准确的描述吗?

1 个答案:

答案 0 :(得分:0)

您的描述准确无误。

这时您可能遇到的最大问题是了解SQL的非过程性质。使用这种语言,您无需指定获取结果所需的步骤,仅描述所需的结果。

因此,对于表中的每一行,您在上方使用的SQL语句希望id增加1。如果数据库是通过内部运行循环或出于天灾来做到这一点,则不是您的主要重点。

这在一开始对许多过程程序员来说很奇怪,但是一旦习惯了,它会使生活变得更好:您不必了解所有数据库内部知识就能找到处理查询的最佳方法。 optimizer 为您做到这一点,通常比您自己做的更好。

当然,好奇的是想知道内部如何处理查询。为此,您可以使用EXPLAIN语句。这对于分析和修复性能问题特别重要。

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