PL/pgSQL 入门教程(二):表达式和基础语句

简介: 本文详解PL/pgSQL核心语法:表达式由主SQL引擎以参数化SELECT执行,支持计划缓存;基础语句涵盖赋值(:=/=)、静态/动态SQL执行(INTO/PERFORM/EXECUTE)、结果处理(STRICT模式)、状态获取(FOUND/GET DIAGNOSTICS)及空操作NULL。

一、表达式

PL/pgSQL 语句所使用的所有表达式,均由服务器的主 SQL 执行器统一处理。

1. 表达式执行原理

  1. 转换为 SELECT 命令

当执行包含表达式的 PL/pgSQL 语句(如 IF expression THEN ...)时,解释器会将该表达式转换为 SELECT expression 语句,提交至主 SQL 引擎执行计算。

例如:

IF x < y THEN ...

底层等价于执行:

PREPARE statement_name(integer, integer) AS SELECT $1 < $2;
EXECUTE statement_name(x, y);
  1. 变量参数化与计划缓存

    • 表达式中的 PL/pgSQL 变量会被替换为查询参数$1$2...),而非直接拼接变量值,从源头规避语法冲突风险;

    • SELECT 语句的执行计划仅需预编译一次,后续调用可复用此计划并传入不同变量值,有效提升执行性能。

  2. 语法限制

表达式对应的 SELECT 命令支持普通 SELECT 的大部分子句,但 包含顶层 UNION INTERSECT EXCEPT 子句,否则将触发语法错误。

  1. 结果要求

表达式对应的 SELECT 语句必须返回单个列,且返回行数不超过 1 行,具体规则如下:

2. 典型示例

判断表是否非空:

IF count(*) > 0 FROM my_table THEN ...

该表达式等价于执行 SELECT count(*) > 0 FROM my_table,系统将根据查询返回的布尔值执行对应分支逻辑。

二、基础语句

2.1 赋值操作

1. 语法格式

variable { := | = } expression;
  • 赋值符:兼容 PL/SQL 风格的 := 与 SQL 风格的 =,两种格式均可正常使用;

  • 目标变量范围:可包括普通变量、行/记录类型的字段、数组元素及数组切片。

2. 表达式求值规则

  • 赋值语句中的表达式,同样会转换为 SELECT 命令执行;

  • 表达式必须返回单个值(若变量是行/记录类型,可返回行值)。

3. 类型转换规则

若表达式结果类型与变量类型不匹配,系统将按以下优先级执行类型转换:

  1. 赋值类型转换:使用预设的类型转换规则;

  2. 文本转换:若无预设规则,先将结果转为字符串(调用类型的输出函数),再转为目标类型(调用目标类型的输入函数),可能触发运行时错误。

4. 示例

tax := subtotal * 0.06; -- 普通变量赋值
my_record.user_id := 20; -- 记录字段赋值
my_array[1:3] := array[1,2,3]; -- 数组切片赋值
complex_array[n].realpart = 12.3; -- 嵌套数组字段赋值

2.2 执行 SQL 命令

PL/pgSQL 中执行 SQL 命令分为静态命令动态命令两类,二者核心差异在于是否支持变量参数化及执行计划缓存机制。

1. 执行无返回行的 SQL 命令

对于无返回行的 SQL 命令,可直接编写执行,例如 CREATE TABLE、无 RETURNING 子句的INSERTUPDATE 等语句,示例如下:


CREATE TABLE mytable (id int primary key, data text);
INSERT INTO mytable VALUES (1,'one'), (2,'two');

2. 执行有返回行的 SQL 命令

针对有返回行的 SQL 命令,需根据返回行数采用对应的处理方式,具体如下表所示:

场景 处理方式
最多返回 1 行 添加 INTO 子句,将结果赋值给变量
返回多行 作为 FOR 循环的数据源,遍历结果

3. 静态 SQL 命令(可优化命令)

适用场景SELECT 语句、带 RETURNING子句的 INSERT/UPDATE/DELETE/MERGE 语句及 EXPLAIN 语句等。

  • 变量参数化:命令中的 PL/pgSQL 变量会自动替换为查询参数,有效防范 SQL 注入攻击;

  • 计划缓存:执行计划会被系统缓存并复用,显著提升语句重复执行时的效率。

4. 丢弃结果的执行:PERFORM 语句

当需执行查询但无需使用返回结果时(如调用具有副作用的函数),需使用 PERFORM 语句替代 SELECT 语句,语法格式如下:

PERFORM query;
  • 语法规范:将常规 SELECT 替换为 PERFORM;若查询包含 WITH 子句,需用括号包裹整个查询语句;

  • 状态反馈:执行完成后,系统会更新特殊变量 FOUND,若查询返回至少 1 行结果则设为 true,无返回结果则设为 false

注意事项:直接使用 SELECT 语句且不搭配 INTO 子句时,将触发语法错误,需优先使用 PERFORM 语句。

5. 非优化命令(工具类命令)

适用 场景CREATE INDEXALTER TABLE 等工具类命令,此类命令不支持变量参数化。

  • 无法自动替换变量,必须通过动态命令拼接字符串执行。

2.3 执行返回单行结果的命令

通过 INTO 子句,可将单行查询结果赋值给记录变量行变量标量变量列表,实现结果的精准接收与后续处理。

1. 语法格式

SELECT select_expressions INTO [STRICT] target FROM ...;
INSERT ... RETURNING expressions INTO [STRICT] target;
UPDATE ... RETURNING expressions INTO [STRICT] target;
DELETE ... RETURNING expressions INTO [STRICT] target;
MERGE ... RETURNING expressions INTO [STRICT] target;

2. 关键参数说明

参数 说明
target 接收结果的变量:单个记录/行变量,或逗号分隔的标量变量列表
STRICT 严格模式:要求命令必须返回且仅返回 1 行结果,若不符合条件则抛出对应异常。

3. 执行规则

  1. 非严格模式(默认)

    • 返回 1 行时,将结果赋值给 target 指定的变量;

    • 返回 0 行时,target 变量值被设为 NULL

    • 返回多行时,仅提取第一行结果赋值,其余行结果将被丢弃;

    • 可通过 FOUND 变量判断是否成功返回数据。

  2. 严格模式(STRICT)

    • 返回 0 行时,抛出 NO_DATA_FOUND 异常;

    • 返回多行时,抛出 TOO_MANY_ROWS 异常;

    • 执行成功时,FOUND 变量自动设为 true

特殊限制:对于带 RETURNING 子句的 INSERT/UPDATE 等命令,即使未指定 STRICT 模式,返回多行结果也会抛出异常。

4. 语法注意事项

  • INTO 子句位置:SELECT 命令中建议置于查询字段前后,其他类型命令建议置于语句末尾,保证语法规范性;

  • 与原生 SELECT INTO 的区别:PL/pgSQL 中 INTO 用于结果赋值,原生命令中 INTO 用于创建表;若需创建表,应使用 CREATE TABLE ... AS SELECT 语句。

5. 调试优化:print_strict_params

启用该选项后,严格模式下触发异常时,会在 DETAIL 信息中显示具体参数值,为问题排查提供便利:

CREATE FUNCTION get_userid(username text) RETURNS int
AS $$
#print_strict_params on
DECLARE userid int;
BEGIN
    SELECT users.userid INTO STRICT userid FROM users WHERE users.username = username;
    RETURN userid;
END;
$$ LANGUAGE plpgsql;

2.4 执行动态命令

当 SQL 命令需动态指定表名、字段名等标识符时,需使用 EXECUTE 语句执行动态拼接的 SQL 字符串,实现灵活适配。

1. 语法格式

EXECUTE command-string [ INTO [STRICT] target ] [ USING expression [, ... ] ];
参数 说明
command-string 动态拼接的 SQL 命令字符串(text 类型)
target 接收结果的变量
USING 传入命令的参数,对应字符串中的 $1$2...

2. 核心特性

  1. 无自动变量替换:需手动将变量拼接至字符串,或通过 USING 子句传入参数,不可依赖系统自动替换;

  2. 无执行计划缓存:每次执行都会重新生成执行计划,适用于动态表/字段等非固定结构的操作场景;

  3. 参数化传值(推荐):通过 USING 子句传入参数,既能避免 SQL 注入风险,又无需手动转义特殊字符,提升安全性与效率。

3. 关键用法示例

场景 示例代码
带参数的动态查询 EXECUTE 'SELECT count(*) FROM mytable WHERE inserted_by = $1' INTO c USING checked_user;
动态表名(安全转义) EXECUTE format('SELECT count(*) FROM %I', tabname) INTO c;
动态字段赋值 EXECUTE format('UPDATE tbl SET %I = $1', colname) USING newvalue;

4. 安全转义函数

拼接动态表名、字段名或变量值时,必须使用指定转义函数,以规避语法错误及 SQL 注入风险,保障命令安全执行:

函数 用途 示例
quote_ident 转义标识符(表名、字段名) quote_ident('my table') → "my table"
quote_literal 转义字符串值(NULL 会返回 NULL quote_literal('a''b') → 'a''b'
quote_nullable 转义值(NULL 会返回字符串 NULL quote_nullable(NULL) → NULL

推荐方案:使用 format 函数的 %I(标识符占位符)和 %L(值占位符),简化转义操作,提升代码可读性。

2.5 获取执行状态

PL/pgSQL 提供两种方式获取命令执行后的状态信息,分别适用于详细指标查询与快速结果判断场景。

1. GET DIAGNOSTICS 命令

用于获取详细的系统状态指标,语法格式如下:

GET [ CURRENT ] DIAGNOSTICS variable { = | := } item [ , ... ];

支持的状态项:

状态项 类型 描述
ROW_COUNT bigint 最近一次 SQL 命令处理的行数
PG_CONTEXT text 当前调用栈信息
PG_ROUTINE_OID oid 当前函数的 OID

示例:

GET DIAGNOSTICS cnt = ROW_COUNT; -- 获取受影响行数

2. FOUND 变量

FOUND 为特殊布尔变量,用于快速判断命令是否产生有效结果。该变量在每次函数调用时初始化为 false,并由以下语句更新状态:

语句类型 FOUND 设为 true 的条件
SELECT INTO 成功返回 1 行
PERFORM 返回至少 1 行
INSERT/UPDATE/DELETE/MERGE 至少影响 1 行
FETCH/MOVE 成功获取/移动游标
FOR/FOREACH 循环至少执行 1 次
RETURN QUERY 查询返回至少 1 行

注意 事项EXECUTE 语句会更新 ROW_COUNT 变量值,但不会修改 FOUND 变量的状态,需单独通过其他方式判断结果。

2.6 空操作语句:NULL

空操作语句(NULL;)用于逻辑占位,无任何实际执行效果,语法格式如下:

NULL;

典型用途:标记 IF/EXCEPTION 等分支的空逻辑,明确代码意图,提升代码可读性与可维护性。

示例:

BEGIN
    y := x / 0;
EXCEPTION
    WHEN division_by_zero THEN
        NULL; -- 明确表示忽略错误
END;
相关文章
|
9天前
|
人工智能 JavaScript Linux
【Claude Code 全攻略】终端AI编程助手从入门到进阶(2026最新版)
Claude Code是Anthropic推出的终端原生AI编程助手,支持40+语言、200k超长上下文,无需切换IDE即可实现代码生成、调试、项目导航与自动化任务。本文详解其安装配置、四大核心功能及进阶技巧,助你全面提升开发效率,搭配GitHub Copilot使用更佳。
|
3天前
|
JSON API 数据格式
OpenCode入门使用教程
本教程介绍如何通过安装OpenCode并配置Canopy Wave API来使用开源模型。首先全局安装OpenCode,然后设置API密钥并创建配置文件,最后在控制台中连接模型并开始交互。
1648 5
|
11天前
|
存储 人工智能 自然语言处理
OpenSpec技术规范+实例应用
OpenSpec 是面向 AI 智能体的轻量级规范驱动开发框架,通过“提案-审查-实施-归档”工作流,解决 AI 编程中的需求偏移与不可预测性问题。它以机器可读的规范为“单一真相源”,将模糊提示转化为可落地的工程实践,助力开发者高效构建稳定、可审计的生产级系统,实现从“凭感觉聊天”到“按规范开发”的跃迁。
1764 18
|
10天前
|
人工智能 JavaScript 前端开发
【2026最新最全】一篇文章带你学会Cursor编程工具
本文介绍了Cursor的下载安装、账号注册、汉化设置、核心模式(Agent、Plan、Debug、Ask)及高阶功能,如@引用、@Doc文档库、@Browser自动化和Rules规则配置,助力开发者高效使用AI编程工具。
1303 7
|
11天前
|
消息中间件 人工智能 Kubernetes
阿里云云原生应用平台岗位急招,加入我们,打造 AI 最强基础设施
云原生应用平台作为中国最大云计算公司的基石,现全面转向 AI,打造 AI 时代最强基础设施。寻找热爱技术、具备工程极致追求的架构师、极客与算法专家,共同重构计算、定义未来。杭州、北京、深圳、上海热招中,让我们一起在云端,重构 AI 的未来。
|
13天前
|
IDE 开发工具 C语言
【2026最新】VS2026下载安装使用保姆级教程(附安装包+图文步骤)
Visual Studio 2026是微软推出的最新Windows专属IDE,启动更快、内存占用更低,支持C++、Python等开发。推荐免费的Community版,安装简便,适合初学者与个人开发者使用。
1317 13
|
9天前
|
人工智能 JSON 自然语言处理
【2026最新最全】一篇文章带你学会Qoder编辑器
Qoder是一款面向程序员的AI编程助手,集智能补全、对话式编程、项目级理解、任务模式与规则驱动于一体,支持模型分级选择与CLI命令行操作,可自动生成文档、优化提示词,提升开发效率。
806 9
【2026最新最全】一篇文章带你学会Qoder编辑器
|
13天前
|
人工智能 测试技术 开发者
AI Coding后端开发实战:解锁AI辅助编程新范式
本文系统阐述了AI时代开发者如何高效协作AI Coding工具,强调破除认知误区、构建个人上下文管理体系,并精准判断AI输出质量。通过实战流程与案例,助力开发者实现从编码到架构思维的跃迁,成为人机协同的“超级开发者”。
1045 93
|
7天前
|
云安全 安全
免费+限量+领云小宝周边!「阿里云2026云上安全健康体检」火热进行中!
诚邀您进行年度自检,发现潜在风险,守护云上业务连续稳健运行
1180 2

热门文章

最新文章