Oracle兼容-语法-EXECUTE IMMEDIATE
1. 语法
1. EXECUTE IMMEDIATE dynamic_sql_stmt
2. [ { into_clause | bulk_collect_into_clause } [ using_clause ]
3. | using_clause
4. ] ;
1. using_clause ::=
3. USING [ IN | OUT | IN OUT ] bind_argument
4. [ [,] [ [ IN | OUT | IN OUT ] bind_argument ]...
1. into_clause ::=
3. INTO { variable [, variable ]... | record )
当 sql_mode 切换到 ORACLE 模式下时,在存储过程中支持如下用法:
1. bulk_collect_into_clause ::=
3. BULK COLLECT INTO { collection | :host_array }
4. [, { collection | :host_array } ]...
2. 定义和用法
EXECUTE IMMEDIATE 用于动态执行SQL语句,是指先把一个SQL命令保存到一个字符串中,然后通过 EXECUTE IMMEDIATE 命令动态执行字符串中的SQL语句,以实现SQL语句的动态生成。
EXECUTE IMMEDIATE 使用时有以下几点注意事项:
-
- 参数
USING支持使用表达式作为预处理变量。
- 参数
-
- 参数
USING OUT/USING IN OUT支持对变量进行赋值。
- 参数
-
- 支持使用
INTO将返回结果赋给变量。
- 支持使用
-
- 在
DYNAMIC_SQL_STMT子句中支持使用变量。
- 在
-
- 在
DYNAMIC_SQL_STMT子句中不支持含有INTO的语法。
- 在
在GreatSQL和Oracle中的差异点及其他注意事项:
DYNAMIC_SQL_STMT子句不支持匿名存储过程(例如:BEGIN SELECT :1, :2; END;)运行。- 在Oracle中,作为
USING OUT时在语法上允许USING OUT TO_CHAR(...)这种语句运行,但会导致Oracle单个进程断开连接,因此如果用到需要USING OUT支持存储过程赋值的情况,将会限制只能使用变量或者系统变量作为参数。
1. > EXECUTE IMMEDIATE 'CALL p1(?)' USING OUT var; <--允许
2. > EXECUTE IMMEDIATE 'CALL p1(?)' USING OUT @var; <--允许
3. > EXECUTE IMMEDIATE 'CALL p1(?)' USING OUT TO_CAHR(@var); <-- 被禁止
- 语句
USING OUT将被视为USING IN OUT。
1. greatsql> DROP PROCEDURE IF EXISTS p1;
2. greatsql> DELIMITER //
3. greatsql> CREATE PROCEDURE IF NOT EXISTS p1(i INT)
4. AS
5. BEGIN
6. i:= 10;
7. END;
9. EXECUTE IMMEDIATE 'CALL p1(?)' USING OUT a;
在GreatSQL中允许这种方式运行,而在Oracle中会报错,要求 USING IN OUT var 或者 USING IN var;
1. > EXECUTE IMMEDIATE 'SELECT ?' USING OUT a;
2. ERROR HY000: Incorrect arguments to using OUT param var only use for call
上述SQL命令在GreatSQL运行时将会引发报错。
- 同时使用
USING IN OUT与INTO属于未定义行为,OUT不一定能够正确赋值。 - 在使用
USING字段的时候,预处理的数据内容需要根据数据类型进行判断的时候,默认将会使用字符串类型,部分函数需要类型转换后才可以使用。
1. greatsql> DELIMITER //
2. greatsql> DECLARE
3. v DATETIME;
4. BEGIN
5. v:= TO_DATE('22:31:23', 'HH24:MI:SS');
6. EXECUTE IMMEDIAtE 'SELECT TO_ChAR(?, ''HH24:MI'')' USING v;
7. END; //
9. ERROR 3064 (HY000): Incorrect type for argument args 0 in function to_char.
11. greatsql> DELIMITER //
12. greatsql> DECLARE
13. v DATETIME;
14. BEGIN
15. v:= TO_DATE('22:31:23', 'hh24:mi:ss');
16. EXECUTE IMMEDIATE 'SELECT TO_CHAR(CAST( ? AS DATETIME) , ''hh24:mi'')' USING v;
17. END; //
18. +-------------------------------------------+
19. | TO_CHAR(CAST( ? AS DATETIME) , 'hh24:mi') |
20. +-------------------------------------------+
21. | 22:31 |
22. +-------------------------------------------+
3. 示例
先创建基本测试表t1:
1. greatsql> DROP TABLE IF EXISTS t1;
2. greatsql> CREATE TABLE IF NOT EXISTS t1
3. (
4. id INT UNSIGNED NOT NULL AUTO_INCREMENT,
5. a INT,
6. PRIMARY KEY(id));
- 支持
DDL、DML、TCL(事务控制语言)语句。
1. EXECUTE IMMEDIATE 'CREATE TABLE t1 (a INT DEFAULT 10, b varchar(255) NOT NULL DEFAULT 1);';
2. EXECUTE IMMEDIATE 'DROP TABLE IF EXISTS t1;';
3. EXECUTE IMMEDIATE 'ALTER TABLE \`t1\` ADD COLUMN \`b\` varchar(255) NOT NULL DEFAULT 1;';
4. EXECUTE IMMEDIATE 'CREATE VIEW v1 AS SELECT * FROM t1;';
5. EXECUTE IMMEDIATE 'DROP VIEW IF EXISTS v1;';
6. EXECUTE IMMEDIATE 'ALTER TABLE t1 ADD INDEX k1 (a) ;';
7. EXECUTE IMMEDIATE 'DROP INDEX k1 ON t1;';
9. EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (2,3)';
10. EXECUTE IMMEDIATE 'UPDATE t1 SET a=3 WHERE a=2;';
11. EXECUTE IMMEDIATE 'DELETE FROM t1 WHERE a=2;';
12. EXECUTE IMMEDIATE 'SELECT * FROM t1;';
13. EXECUTE IMMEDIATE 'ROLLBACK';
14. EXECUTE IMMEDIATE 'COMMIT;';
- 支持
SET赋值临时变量。
1. EXECUTE IMMEDIATE 'SET @param=(SELECT a FROM t1 LIMIT 1);';
2. SELECt @param;
- 支持利用
USING绑定参数与表达式。
1. greatsql> SET @a=1;
2. greatsql> EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?,1)' USING @a;
3. Query OK, 1 row affected (0.00 sec)
5. greatsql> EXECUTE IMMEDIATE 'SELECT ?' USING TO_CHAR(1);
6. +------+
7. | ? |
8. +------+
9. | 1 |
10. +------+
12. -- 切换sql_mode为ORACLE
13. greatsql> SET sql_mode = ORACLE;
14. greatsql> DELIMITER //
15. greatsql> DECLARE
16. v1 INT:= 2;
17. BEGIN
18. EXECUTE IMMEDIATE 'SELECT ?' USING v1;
19. END; //
20. +------+
21. | ? |
22. +------+
23. | 2 |
24. +------+
- 支持存储过程中使用 EXECUTE IMMEDIATE。
1. greatsql> DROP PROCEDURE IF EXISTS p1;
2. greatsql> DELIMITER //
3. CREATE PROCEDURE IF NOT EXISTS p1 (x int)
4. BEGIN
5. SET @a = x;
6. EXECUTE IMMEDIATE 'SELECT * FROM t1 WHERE a = ?;' USING @a;
7. EXECUTE IMMEDIATE 'ALTER TABLE \`t1\` add column \`c\` VARCHAR(255) NOT NULL DEFAULT 123456;';
8. EXECUTE IMMEDIATE 'SELECT * FROM t1 WHERE a = ?;' USING @a;
9. END; //
11. greatsql> CALL p1(1); //
12. +----+------+
13. | id | a |
14. +----+------+
15. | 1 | 1 |
16. +----+------+
17. 1 row in set (0.00 sec)
19. +----+------+--------+
20. | id | a | c |
21. +----+------+--------+
22. | 1 | 1 | 123456 |
23. +----+------+--------+
- 调用存储过程。
1. greatsql> DROP PROCEDURE IF EXISTS p2;
2. greatsql> DELIMITER //
3. greatsql> CREATE PROCEDURE IF NOT EXISTS p2(OUT a INT)
4. BEGIN
5. SET a:= 10;
6. SELECT CONCAT("IN a=", a);
7. END; //
9. greatsql> DELIMITER ;
10. greatsql> SET @a = 2;
11. greatsql> EXECUTE IMMEDIATE 'CALL p2(?)' USING @a;
12. +--------------------+
13. | CONCAT("IN a=", a) |
14. +--------------------+
15. | IN a=10 |
16. +--------------------+
18. greatsql> SELECT @a;
19. +------+
20. | @a |
21. +------+
22. | 2 |
23. +------+
25. -- 注意和上例多了个 OUT 关键字后,返回结果不同
26. greatsql> EXECUTE IMMEDIATE 'CALL p2(?)' USING OUT @a;
27. +--------------------+
28. | CONCAT("IN a=", a) |
29. +--------------------+
30. | IN a=10 |
31. +--------------------+
33. greatsql> SELECT @a;
34. +------+
35. | @a |
36. +------+
37. | 10 |
38. +------+
40. greatsql> DROP PROCEDURE IF EXISTS p2;
- 变量作为语句。
1. greatsql> SET @v = 'SELECT "GreatSQL"';
3. greatsql> EXECUTE IMMEDIATE @v;
4. +----------+
5. | GreatSQL |
6. +----------+
7. | GreatSQL |
8. +----------+
- 支持存储过程中的变量作为语句。
1. -- 切换sql_mode为ORACLE
2. greatsql> SET sql_mode = ORACLE;
3. greatsql> DELIMITER //
4. greatsql> DECLARE
5. v VARCHAR(200);
6. BEGIN
7. v:= 'SELECT \'GreatSQL\', ' || TO_CHAR(3306);
9. EXECUTE IMMEDIATE v;
10. END; //
12. +----------+------+
13. | GreatSQL | 3306 |
14. +----------+------+
15. | GreatSQL | 3306 |
16. +----------+------+
- 支持用
INTO/BULK COLLECT INTO获取查询结果。
1. greatsql> EXECUTE IMMEDIATE 'SELECT \'GreatSQL\'' INTO @v;
3. greatsql> SELECT @v;
4. +----------+
5. | @v |
6. +----------+
7. | GreatSQL |
8. +----------+
10. greatsql> SET sql_mode = ORACLE;
11. greatsql> DELIMITER //
12. greatsql> DECLARE
13. v1 INT := 2;
14. BEGIN
15. EXECUTE IMMEDIATE 'SELECT ?' INTO v1 USING 1;
16. SELECT v1;
17. END; //
19. +------+
20. | v1 |
21. +------+
22. | 1 |
23. +------+
25. greatsql> SET sql_mode = ORACLE;
26. greatsql> DELIMITER //
27. greatsql> DECLARE
28. TYPE 1type IS RECORD
29. (
30. a INT
31. );
32. TYPE array_param_type IS TABLE OF 1type;
33. ary array_param_type;
34. BEGIN
35. EXECUTE IMMEDIATE 'SELECT a FROM t1' BULK COLLECT INTO ary;
36. SELECT ary;
37. END; //
39. +----------------------------+
40. | ary |
41. +----------------------------+
42. | ARRAY_PARAM_TYPE(1type(1)) |
43. +----------------------------+
- 不支持使用非定义参数。
1. greatsql> CREATE TABLE t3 (a INT DEFAULT 10);
2. greatsql> EXECUTE IMMEDIATE 'INSERT INTO t3 VALUES (?)' USING DEFAULT;
3. ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
- 不支持数据库切换语句。
1. greatsql> EXECUTE IMMEDIATE 'USE greatsql;';
2. ERROR 1295 (HY000): This command is not supported in the prepared statement protocol yet
- 不支持创建/删除存储过程。
1. greatsql> EXECUTE IMMEDIATE 'CREATE PROCEDURE p5(x int) BEGIN SET @a = x; END;';
2. ERROR 1295 (HY000): This command is not supported in the prepared statement protocol yet
4. greatsql> EXECUTE IMMEDIATE 'drop PROCEDURE p1;';
5. ERROR 1295 (HY000): This command is not supported in the prepared statement protocol yet
- 不支持创建/删除函数。
1. greatsql> EXECUTE IMMEDIATE 'CREATE FUNCTION f1(a int) RETURNS INT BEGIN RETURN a * 10; END;';
2. ERROR 1295 (HY000): This command is not supported in the prepared statement protocol yet
4. greatsql> EXECUTE IMMEDIATE 'DROP FUNCTION f1;';
5. ERROR 1295 (HY000): This command is not supported in the prepared statement protocol yet
- 不支持创建/删除触发器。
1. greatsql> EXECUTE IMMEDIATE 'CREATE TRIGGER trig1 BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + NEW.c0;';
2. ERROR 1295 (HY000): This command is not supported in the prepared statement protocol yet
4. greatsql> EXECUTE IMMEDIATE 'drop TRIGGER IF EXISTS trig1;';
5. ERROR 1295 (HY000): This command is not supported in the prepared statement protocol yet
- 不支持handler使用。
1. greatsql> EXECUTE IMMEDIATE 'handler test_number open;';
2. ERROR 1295 (HY000): This command is not supported in the prepared statement protocol yet
- 不支持开始事务操作。
1. greatsql> EXECUTE IMMEDIATE 'START TRANSACTION;';
2. ERROR 1295 (HY000): This command is not supported in the prepared statement protocol yet
- 不支持语句中带有INTO。
1. greatsql> EXECUTE IMMEDIATE 'SELECT 1 INTO @v;';
2. ERROR HY000: Misplaced INTO clause, INTO is not allowed inside EXECUTE IMMEDIATE query string
问题反馈
联系我们
扫码关注微信公众号

