2025年9月25日: PostgreSQL 18 发布!
支持版本:当前 (18) / 17 / 16 / 15 / 14 / 13
开发版本:devel
不支持的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4

34.5. 动态 SQL #

在许多情况下,应用程序需要执行的特定 SQL 语句在应用程序编写时就已经知道了。然而,在某些情况下,SQL 语句是在运行时组合的,或者由外部源提供。在这些情况下,您不能将 SQL 语句直接嵌入到 C 源代码中,但有一种机制允许您调用在字符串变量中提供的任意 SQL 语句。

34.5.1. 执行不带结果集的语句 #

执行任意 SQL 语句的最简单方法是使用 EXECUTE IMMEDIATE 命令。例如:

EXEC SQL BEGIN DECLARE SECTION;
const char *stmt = "CREATE TABLE test1 (...);";
EXEC SQL END DECLARE SECTION;

EXEC SQL EXECUTE IMMEDIATE :stmt;

EXECUTE IMMEDIATE 可用于不返回结果集的 SQL 语句(例如,DDL、INSERTUPDATEDELETE)。您不能通过这种方式执行检索数据的语句(例如,SELECT)。下一节将介绍如何做到这一点。

34.5.2. 执行带输入参数的语句 #

执行任意 SQL 语句的更强大方法是准备一次语句,然后根据需要多次执行准备好的语句。还可以准备一个语句的通用版本,然后通过替换参数来执行该语句的特定版本。在准备语句时,在您希望稍后替换参数的位置写上问号。例如:

EXEC SQL BEGIN DECLARE SECTION;
const char *stmt = "INSERT INTO test1 VALUES(?, ?);";
EXEC SQL END DECLARE SECTION;

EXEC SQL PREPARE mystmt FROM :stmt;
 ...
EXEC SQL EXECUTE mystmt USING 42, 'foobar';

当您不再需要准备好的语句时,应该将其释放:

EXEC SQL DEALLOCATE PREPARE name;

34.5.3. 执行带结果集的语句 #

要执行带单个结果行的 SQL 语句,可以使用 EXECUTE。要保存结果,请添加 INTO 子句。

EXEC SQL BEGIN DECLARE SECTION;
const char *stmt = "SELECT a, b, c FROM test1 WHERE a > ?";
int v1, v2;
VARCHAR v3[50];
EXEC SQL END DECLARE SECTION;

EXEC SQL PREPARE mystmt FROM :stmt;
 ...
EXEC SQL EXECUTE mystmt INTO :v1, :v2, :v3 USING 37;

EXECUTE 命令可以带有 INTO 子句、USING 子句、两者都有,或者两者都没有。

如果查询预计返回多于一个结果行,则应使用游标,如下例所示。(有关游标的更多详细信息,请参阅第 34.3.2 节。)

EXEC SQL BEGIN DECLARE SECTION;
char dbaname[128];
char datname[128];
char *stmt = "SELECT u.usename as dbaname, d.datname "
             "  FROM pg_database d, pg_user u "
             "  WHERE d.datdba = u.usesysid";
EXEC SQL END DECLARE SECTION;

EXEC SQL CONNECT TO testdb AS con1 USER testuser;
EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;

EXEC SQL PREPARE stmt1 FROM :stmt;

EXEC SQL DECLARE cursor1 CURSOR FOR stmt1;
EXEC SQL OPEN cursor1;

EXEC SQL WHENEVER NOT FOUND DO BREAK;

while (1)
{
    EXEC SQL FETCH cursor1 INTO :dbaname,:datname;
    printf("dbaname=%s, datname=%s\n", dbaname, datname);
}

EXEC SQL CLOSE cursor1;

EXEC SQL COMMIT;
EXEC SQL DISCONNECT ALL;

提交更正

如果您在文档中发现任何不正确、不符合您对特定功能的经验,或需要进一步澄清的内容,请使用此表单报告文档问题。