0Pricing
SQL Academy · 课时

PL/pgSQL 函数基础

编写带参数的 PL/pgSQL 函数,使用 RETURNS TABLE、控制流(IF、LOOP、FOREACH)和异常处理

PL/pgSQL 函数基础 是 CoddyKit 上的免费 SQL Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 SQL Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 SQL Academy 课程共包含 4 节课。

什么是 PL/pgSQL

PostgreSQL 内置的过程式语言。在 SQL 基础上扩展了变量、控制流、异常处理以及动态调用查询的能力。用于存储过程和触发器函数。

函数骨架

一个简单的函数:

CREATE OR REPLACE FUNCTION add(a INT, b INT)
RETURNS INT AS $$
BEGIN
  RETURN a + b;
END;
$$ LANGUAGE plpgsql IMMUTABLE;

SELECT add(2, 3);   -- 5

变量

使用 DECLARE 声明;使用 := 或 INTO 赋值:

CREATE FUNCTION user_orders(uid BIGINT)
RETURNS INT AS $$
DECLARE
  cnt INT;
BEGIN
  SELECT COUNT(*) INTO cnt FROM orders WHERE user_id = uid;
  RETURN cnt;
END;
$$ LANGUAGE plpgsql STABLE;

控制流

IF / ELSE、FOR、WHILE、CASE:

IF cnt = 0 THEN
  RAISE NOTICE 'no orders';
ELSIF cnt < 10 THEN
  RAISE NOTICE 'few';
ELSE
  RAISE NOTICE 'many';
END IF;

FOR i IN 1..10 LOOP
  RAISE NOTICE '%', i;
END LOOP;

遍历查询结果

类似游标的迭代:

CREATE FUNCTION recalc_totals() RETURNS VOID AS $$
DECLARE
  r RECORD;
BEGIN
  FOR r IN SELECT id FROM users LOOP
    UPDATE users SET
      order_count = (SELECT COUNT(*) FROM orders WHERE user_id = r.id)
    WHERE id = r.id;
  END LOOP;
END;
$$ LANGUAGE plpgsql;

RETURNS TABLE

返回结果集:

CREATE FUNCTION top_buyers(n INT)
RETURNS TABLE (user_id BIGINT, total NUMERIC) AS $$
BEGIN
  RETURN QUERY
    SELECT o.user_id, SUM(o.total)
    FROM orders o
    GROUP BY o.user_id
    ORDER BY SUM(o.total) DESC
    LIMIT n;
END;
$$ LANGUAGE plpgsql STABLE;

SELECT * FROM top_buyers(10);

IN / OUT / INOUT 参数

返回多个值:

CREATE FUNCTION stats(uid BIGINT,
  OUT total NUMERIC,
  OUT cnt INT) AS $$
BEGIN
  SELECT SUM(total), COUNT(*) INTO total, cnt
  FROM orders WHERE user_id = uid;
END;
$$ LANGUAGE plpgsql STABLE;

SELECT * FROM stats(42);   -- total | cnt

异常处理

BEGIN ... EXCEPTION WHEN ... THEN:

BEGIN
  INSERT INTO users (email) VALUES ($1);
EXCEPTION
  WHEN unique_violation THEN
    RAISE NOTICE 'email already exists';
  WHEN OTHERS THEN
    RAISE;
END;

使用 RAISE 记录日志

级别:DEBUG、LOG、INFO、NOTICE、WARNING、EXCEPTION:

RAISE NOTICE 'processed % rows', cnt;
RAISE EXCEPTION 'bad state: %', state USING ERRCODE = 'check_violation';

易变性标记

为规划器正确标记函数:

  • IMMUTABLE — 相同参数始终得到相同结果(不进行输入输出);允许内联和可用于索引的调用
  • STABLE — 在一次查询中,相同参数得到相同结果
  • VOLATILE — 每次调用的结果可能不同(默认值;适用于 NOW()、RANDOM())

SECURITY DEFINER

以函数所有者的权限运行——请谨慎使用:

CREATE FUNCTION sensitive_op() RETURNS VOID
LANGUAGE plpgsql
SECURITY DEFINER
AS $$ ... $$;

-- Always set search_path explicitly to avoid hijacking:
ALTER FUNCTION sensitive_op() SET search_path = public, pg_temp;

回顾

PL/pgSQL 使用循环、IF、异常和结构化返回扩展了 SQL。对于适合在数据附近运行的连贯多步骤逻辑,请使用它。

快速检查

对于给定相同参数始终返回相同结果,且没有副作用或输入/输出的函数,应使用哪种易变性标记?

常见问题解答

「PL/pgSQL 函数基础」课时是免费的吗?

是的 — 「PL/pgSQL 函数基础」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 SQL Academy 课程的其余内容,请升级到 CoddyKit PRO。 SQL Academy 课程共包含 4 节课。

「PL/pgSQL 函数基础」这节课中我会学到什么?

编写带参数的 PL/pgSQL 函数,使用 RETURNS TABLE、控制流(IF、LOOP、FOREACH)和异常处理 你通过在浏览器中直接运行的动手代码来练习 SQL Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 SQL Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 SQL Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「PL/pgSQL 函数基础」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 SQL Academy 课中编写并运行代码吗?

能。每节 SQL Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 触发器剖析:BEFORE/AFTER、FOR EACH ROW
  2. PL/pgSQL 函数基础
  3. DO 块与匿名代码
  4. 使用触发器审计表
← 返回 SQL Academy