ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 33.5\. 动态SQL 在许多情况下,应用要执行的具体的SQL语句在书写应用的时候就已经知道了。 不过,在某些情况下,SQL语句是在运行时或者由外部的数据提供的。 在这种情况下,我们不能直接在C代码嵌入SQL语句, 但是有个机制可以允许你调用放在一个字串变量里的任何SQL语句。 ## 33.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`可以用于不返回结果集 (比如,DDL, `INSERT`, `UPDATE`, `DELETE`)的SQL语句。 你不能用这种方式执行检索数据(比如`SELECT`)的语句。 下一节将描述该如何做。 ## 33.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_; ``` ## 33.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`子句,也可以两个都有或者两个都没有。 如果查询希望返回多个结果行,那么使用游标,正如下面例子。 参阅[Section 33.3.2](#calibre_link-1994)获取更多关于游标的信息。 ``` 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 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; ```