
informix函数使用教程:新手完成第一张作品的方法
在 Informix 中,“函数”既可以指 UPPER、TODAY 这类内置函数,也可以指开发者用 SPL(Stored Procedure Language,存储过程语言)编写的用户自定义函数。前者适合直接处理查询结果;后者可以把一段重复使用的业务计算封装起来,在 SQL 查询中调用。
本文会带你完成一个小作品:创建订单明细表,编写计算行金额的 SPL 函数,再用查询验证结果。示例面向 Informix 常见的 SPL 标量函数写法。不同 Informix 版本、客户端工具和数据库设置可能影响具体语法支持,正式使用前应在目标环境中执行并确认。
一、先弄清楚什么情况下该用函数
函数的价值不只是减少代码。把相同的计算逻辑集中在一个地方,可以降低多个查询各自实现、结果却不一致的风险。常见场景包括:
- 查询中的格式和转换:使用
UPPER统一大小写,使用日期、字符串或数值函数处理字段。 - 反复出现的标量计算:例如根据数量和单价计算金额,或将一组稳定的业务规则封装成返回单个值的函数。
- 在查询表达式中复用逻辑:自定义函数可以出现在适用的 SQL 表达式位置,例如
SELECT列表或筛选条件中。具体可调用位置受函数类型和 SQL 语句限制。
如果只需完成一次简单计算,普通 SQL 表达式通常更直接;如果逻辑要在多个查询或应用中重复使用,才值得考虑自定义函数。需要返回多行结果或执行一组独立操作时,也不应把标量函数当成所有问题的通用容器,应根据需求考虑游标、表函数或存储过程等机制。
二、运行示例前的准备
以下 SQL 可在连接到目标 Informix 数据库后执行。实际操作时,请使用支持 Informix SQL 的客户端,例如 dbaccess。执行建表语句需要相应的建表权限;创建函数通常也需要数据库允许创建例程,并满足当前版本和数据库的权限要求。
先建立一张简单的订单明细表:
CREATE TABLE order_line_demo (
line_id INTEGER,
quantity INTEGER,
unit_price DECIMAL(10,2)
);
插入两条测试数据:
INSERT INTO order_line_demo (line_id, quantity, unit_price)
VALUES (1, 3, 12.50);
INSERT INTO order_line_demo (line_id, quantity, unit_price)
VALUES (2, 2, 8.75);
本例不使用自增列,是为了让示例避免依赖特定的键生成方式。实际表结构可以使用适合项目和 Informix 版本的主键定义。
三、编写第一个 SPL 函数
接下来创建一个返回单个数值的函数。它接收数量和单价,返回二者相乘的金额:
CREATE FUNCTION line_amount(p_quantity INTEGER, p_unit_price DECIMAL(10,2))
RETURNING DECIMAL(12,2);
DEFINE v_amount DECIMAL(12,2);
IF p_quantity IS NULL OR p_unit_price IS NULL THEN
RETURN NULL;
END IF;
LET v_amount = p_quantity * p_unit_price;
RETURN v_amount;
END FUNCTION;
逐段看这段代码:
CREATE FUNCTION定义一个用户自定义函数,名称是line_amount。- 括号中的内容是输入参数及其类型。
p_quantity是整数,p_unit_price是定点小数。 RETURNING DECIMAL(12,2)声明函数返回一个小数值。返回类型要与业务需要匹配,不能只看测试数据的大小;设计时还要考虑最大数量、单价和计算结果范围。DEFINE声明函数内部变量,LET给变量赋值。RETURN返回结果并结束当前函数执行。
上面的空行和缩进只为阅读方便,不影响逻辑。执行例程定义时,客户端需要把从 CREATE FUNCTION 到 END FUNCTION 的内容作为一个完整语句提交。若工具在分号处理上有特殊设置,应按该工具的 Informix 例程执行方式提交,不要把函数体中的语句误拆成多个独立 SQL 命令。
四、调用函数,完成第一张“作品”
先直接调用函数,确认输入和输出:
SELECT line_amount(3, 12.50)
FROM systables
WHERE tabid = 1;
这里用 Informix 系统目录表 systables 中的单行作为查询来源。运行后应得到 37.50。如果当前环境不允许读取该表,可改用已存在的一行表,或直接在订单明细查询中验证。
更接近实际使用的方式,是把函数应用到表的每一行:
SELECT
line_id,
quantity,
unit_price,
line_amount(quantity, unit_price) AS amount
FROM order_line_demo
ORDER BY line_id;
预期得到两行结果:第一行金额为 37.50,第二行金额为 17.50。查询中的 AS amount 为计算列指定了输出名称,并没有修改表里的数据。
也可以用函数构造筛选条件:
SELECT line_id, quantity, unit_price
FROM order_line_demo
WHERE line_amount(quantity, unit_price) > 20.00;
这个查询会筛出金额大于 20 的明细行。函数能否放在某个特定 SQL 子句中,需要结合函数类别、表达式规则及目标版本验证;遇到语法错误时,应先检查调用位置,而不是立即认定函数本身没有创建成功。
五、NULL 是自定义函数必须认真处理的边界
SQL 的 NULL 表示未知或缺失,不等同于数字 0,也不等同于空字符串。算术表达式一旦包含 NULL,结果通常也会是 NULL;比较结果也可能是未知,而不是简单的真或假。因此,不能把“参数为空时怎么办”留给偶然行为决定。
本例显式规定:数量或单价任意一个为 NULL,函数就返回 NULL。可以用下面的查询检查这项约定:
SELECT line_amount(NULL, 12.50)
FROM systables
WHERE tabid = 1;
如果业务规则要求空数量按 0 处理,应明确写出这种规则,并确认数据库中的类型转换符合预期;不要把“缺少数据”悄悄当成零。对需要区分缺失、无效和零值的业务,应在数据模型或查询逻辑中保留这种区别。
还要注意:数据库列是否允许 NULL,由列定义决定;函数参数声明一个数据类型,并不自动替调用者验证业务输入。函数当前示例处理了空值,但没有规定数量必须非负、单价必须非负。这些约束应按业务需求决定,并在写入规则、表约束或函数逻辑中明确落实。
六、Informix 内置函数:优先使用现成工具
并非每个转换都值得写成 SPL。Informix 自带大量 SQL 函数,常见字符串处理可以直接写在查询中:
SELECT
UPPER('informix') AS upper_text,
LENGTH('Informix') AS text_length
FROM systables
WHERE tabid = 1;
结果会包含大写后的文本和字符串长度。使用字符串函数时,应留意字符集、字符长度与版本的具体行为;尤其是多字节字符,不要简单假设字符个数、字节数和存储长度一定相同。
日期处理可以使用 Informix 的日期表达式和日期函数。例如,下面的查询以当前日期为基础,筛选某个日期列早于今天的记录:
SELECT line_id
FROM order_line_demo
WHERE CURRENT > TODAY;
这段查询只是展示日期表达式的位置,并不适用于订单明细表,因为示例表没有日期列,因此执行会报“找不到列”一类错误。把它用于真实表时,必须将条件替换为该表中实际存在且类型适合比较的日期或日期时间列。选择日期类型、当前日期或当前时间函数时,还要确认业务需要的精度与时区语义,不要把日期和时间戳混为一谈。
处理可能为空的表达式时,可根据版本支持情况使用标准的 COALESCE,选择第一个非空值。例如:
SELECT COALESCE(unit_price, 0.00)
FROM order_line_demo;
这条语句把空单价显示为 0.00,但这只是查询表达式的处理方式,不会改变表中数据,也不意味着所有业务都应该把空值解释为零。使用函数或表达式时,先确认当前 Informix 版本支持对应语法,并在需要时查询该版本的 SQL 参考手册。
七、参数和返回值的边界
创建 SPL 函数时,参数和返回值都需要声明类型。类型选择会影响可接受的输入、计算精度和可用范围。例如,金额通常适合使用明确精度和小数位数的 DECIMAL,不应为了省事一律使用整数或近似浮点类型。
- 数值范围:乘法结果的精度和范围应覆盖业务最大值。输入类型能分别容纳两个参数,不代表结果类型一定容得下乘积;应针对边界数据测试。
- 参数数量和长度:Informix 对例程的具体限制可能与版本、例程类型及数据类型有关。不要从其他数据库的规则推断 Informix 的最大参数数目或字符串上限;需要上限时查目标版本文档并在目标实例验证。
- 可空性:参数声明描述数据类型,不应替代对空值行为的设计。对函数的每个输入,最好明确其可否为空及为空时的业务定义。
- 返回值:本文是标量函数,一次调用返回一个值。它不是用来直接返回任意数量查询行的通用接口。需要多行结果时,要选择适合的表函数、游标或其他数据库接口,并按对应语法实现。
- 重载和类型解析:不同版本对例程名称、参数类型和重载的支持与解析细节应以对应版本文档为准。初学时尽量使用清晰、唯一的函数名,并在调用处使用与声明匹配的类型。
八、权限与安全:函数不是自动的安全边界
创建函数、执行函数和访问函数内部涉及的表,是不同层面的权限问题。需要让其他用户调用时,应由数据库管理员或具有相应授权能力的账号配置恰当的例程权限;具体授权语法、例程所有者权限及执行时的权限检查行为,应按所在 Informix 版本和部署配置核实,不要默认创建者权限会自动适用于所有调用者。
函数也不是因为封装在数据库里就自动安全。它可能返回敏感数据、执行有影响的 SQL,或把输入用于动态 SQL。应遵循最小权限原则,只授予调用者完成工作所需的访问能力;上线前检查函数体读取和修改了哪些对象,并确认这些操作符合预期。
本例没有拼接动态 SQL,因此没有动态 SQL 注入入口。若将来必须根据输入动态选择查询内容,不要把用户输入直接拼接成 SQL 字符串;优先使用应用层的参数化查询,并限制可选择的对象名称和操作。对象名通常不能像普通数据值那样简单作为绑定参数处理,更不能因为使用了 SPL 函数就省略输入校验。还应避免把数据库错误信息、敏感字段或内部结构不必要地暴露给普通调用者。
九、常见错误与排查顺序
1. 把函数体拆开执行
创建函数是一个包含多个内部语句的例程定义。若 SQL 客户端只提交了函数头,或在内部第一个分号处截断,数据库就会报告语法错误。检查客户端是否按完整例程提交,并确认脚本分隔方式适配该工具。
2. 参数或返回值类型不匹配
函数声明为整数参数,却传入不兼容表达式,或返回值超出声明范围,都可能导致转换错误或结果无法符合预期。检查调用表达式的实际类型、隐式转换和结果范围,必要时用明确的类型转换,并用业务最大值做测试。
3. 忽略 NULL
查询结果意外变成空值,常见原因是参与运算的列中有 NULL。先分别检查函数的每个输入,再决定函数应该返回空值、采用默认值,还是拒绝该输入;不要只在显示层遮盖问题。
4. 函数名称冲突或调用到了不同对象
不同用户、数据库或例程可能存在同名对象。出现“找不到函数”或调用行为与预期不同,应确认当前连接的数据库、函数所有者、对象名称以及目标环境中实际创建的定义。团队环境中可采用一致的命名规范,避免与内置函数或已有业务例程混淆。
5. 认为函数可以替代表约束
在查询中计算金额,不等于数据库已经把金额保存到表中;筛选结果也不等于写入数据时自动验证输入。如果需要阻止非法数据入库,应设计合适的列类型、约束或写入路径,不要只依赖某个查询恰好调用了函数。
6. 在大查询中盲目调用复杂函数
对很多行调用函数会增加执行工作量。简单表达式有时可以直接写在 SQL 中,优化器也未必能把用户自定义函数当成普通运算进行同样的优化。对大表查询,应查看实际执行计划、测试代表性数据量,并评估筛选条件、索引和函数调用的成本,而不是凭单次小数据测试推断性能。
十、交付前的验证清单
把第一版函数交给别人使用前,可以按下面的顺序检查:
- 在目标数据库中确认函数已成功创建,并记录函数名、输入参数类型、返回类型和适用数据库。
- 用正常输入验证计算结果,例如数量 3、单价 12.50 应返回 37.50。
- 分别测试空参数、零值、负数和接近业务上限的数值,确认处理结果符合约定。
- 确认调用者拥有所需权限,并验证没有无关的数据访问权限被一并开放。
- 用真实查询调用函数,检查列类型、结果精度和查询性能。
- 若部署到测试或生产环境,先核对数据库版本、权限、依赖对象和部署脚本执行方式。
总结
完成第一个 Informix 函数的关键步骤是:先决定逻辑是否值得复用,再明确参数和返回类型,写清楚 NULL 与边界值的处理方式,最后通过 SQL 查询验证结果。本文的 line_amount 展示了 SPL 标量函数的基本结构,也演示了如何在查询中调用它。
刚开始时,优先使用 Informix 内置函数处理简单需求;确实需要共享业务逻辑时,再创建自定义函数。对类型上限、权限行为、客户端脚本分隔和版本差异,不靠猜测,直接以目标 Informix 实例和对应版本文档验证。这比只让示例“跑通一次”更可靠,也更容易把函数安全地用于真实项目。




