Oracle兼容-存储过程-BULK COLLECT


1. 语法

  1. [SELECT|FETCH] .. BULK COLLECT INTO

2. 定义和用法

GreatSQL存储过程中支持用 SELECT|FETCH .. BULK COLLECT INTO 获取多行数据。该用法如下所述:

    1. 支持用 SELECT .. BULK COLLECT INTO 语法取表中多行数据,并赋值给 TABLE 类型变量。
    1. 支持用 FETCH .. BULK COLLECT INTO .. LIMIT n 语法取游标中的多行数据,并赋值给 TABLE 类型变量。

3. Oracle兼容说明

ORACLE 模式下,GreatSQL存储过程支持 [SELECT|FETCH] .. BULK COLLECT INTO 用法。该用法如下所述:

  1. [SELECT|FETCH] .. BULK COLLECT INTO var 中的变量 var 只支持一层表类型,比如 var,不支持 a.b.var 这种变量类型。

  2. FETCH .. BULK COLLECT INTO var 中如果不加 LIMIT n 子句,则默认一次性最多读取 @@select_bulk_into_batch 行数据,其可选范围 [1, 65535],默认值为 10000。如果制定了 LIMIT n 子句,但 n > @@select_bulk_into_batch 时,会提示错误:ER_WRONG_BATCH_FOR_BULK_INTO,这是为了保证不发生内存溢出。

  3. 新增系统选项 select_bulk_into_batch 使用说明:

参数说明
参数名称select_bulk_into_batch
参数解释FETCH .. BULK COLLECT INTO var 时一次性最多读取的行数限制
参数类型INT
参数取值范围(行)[1, 65535]
默认值(行)10000
建议最佳数值(行)1000
使用示例SET @@select_bulk_into_batch = n;
SHOW VARIABLES LIKE ‘select_bulk_into_batch’;

4. 示例

修改 sql_generate_invisible_primary_key 选项设定,因为下面案例中创建的表没有显式主键,关闭该选项可以避免自动创建隐式主键 my_row_id,可能会对下面的案例造成影响。

  1. greatsql> SET SESSION sql_generate_invisible_primary_key = 0;

创建测试表并初始化数据

  1. greatsql> CREATE TABLE t1 (a INT NOT NULL, b VARCHAR(20) NOT NULL);
  2. greatsql> INSERT INTO t1 VALUES(1, 'row1'), (2, 'row2'), (3,'row3') ;
  3. greatsql> CREATE TABLE t2 (a INT NOT NULL, b VARCHAR(20) NOT NULL);
    1. 示例1:SELECT BULK COLLECT
  1. greatsql> SET sql_mode = ORACLE;
  2. greatsql> DELIMITER //
  3. CREATE OR REPLACE PROCEDURE bulk_sp1() AS
  4. TYPE udtt IS TABLE OF t1%ROWTYPE INDEX BY BINARY_INTEGER;
  5. udtt_t1 udtt;
  6. BEGIN
  7. SELECT * BULK COLLECT INTO udtt_t1 FROM t1;
  8. FOR i IN udtt_t1.FIRST .. udtt_t1.LAST LOOP
  9. SELECT udtt_t1(i).a, udtt_t1(i).b;
  10. END LOOP;
  11. END; //
  12. greatsql> CALL bulk_sp1() //
  13. +--------------+--------------+
  14. | udtt_t1(i).a | udtt_t1(i).b |
  15. +--------------+--------------+
  16. | 1 | row1 |
  17. +--------------+--------------+
  18. 1 row in set (0.00 sec)
  19. +--------------+--------------+
  20. | udtt_t1(i).a | udtt_t1(i).b |
  21. +--------------+--------------+
  22. | 2 | row2 |
  23. +--------------+--------------+
  24. 1 row in set (0.00 sec)
  25. +--------------+--------------+
  26. | udtt_t1(i).a | udtt_t1(i).b |
  27. +--------------+--------------+
  28. | 3 | row3 |
  29. +--------------+--------------+
  30. 1 row in set (0.00 sec)
  31. Query OK, 0 rows affected (0.00 sec)
    1. 示例2:FETCH BULK COLLECT
  1. greatsql> SET sql_mode = ORACLE;
  2. greatsql> DELIMITER //
  3. greatsql> CREATE OR REPLACE PROCEDURE bulk_sp2(v_a INT) AS
  4. TYPE t1_record IS RECORD(
  5. id INT := 1,
  6. name_d VARCHAR(20)
  7. );
  8. TYPE t1_list IS TABLE OF t1_record INDEX BY BINARY_INTEGER;
  9. t1_record_val t1_list;
  10. CURSOR c(v_a INT) IS SELECT a, b FROM t1 WHERE a = v_a;
  11. BEGIN
  12. OPEN c(v_a);
  13. -- 这里实际只获取到两行数据,而LIMIT限定为3,不会报错
  14. FETCH c BULK COLLECT INTO t1_record_val LIMIT 3;
  15. -- 目前FORALL后面只支持INSERT操作
  16. FORALL i IN t1_record_val.FIRST .. t1_record_val.LAST
  17. INSERT INTO t2 VALUES t1_record_val(i);
  18. CLOSE c;
  19. END; //
  20. greatsql> CALL bulk_sp2(1) //
  21. Query OK, 1 row affected (0.00 sec)
  22. greatsql> SELECT * FROM t2 //
  23. +---+------+
  24. | a | b |
  25. +---+------+
  26. | 1 | row1 |
  27. +---+------+
  28. 1 row in set (0.01 sec)
    1. 示例3:FETCH BULK COLLECT INTO batch
  1. greatsql> SET sql_mode = ORACLE;
  2. greatsql> SET select_bulk_into_batch = 5;
  3. greatsql> DELIMITER //
  4. greatsql> CREATE OR REPLACE PROCEDURE bulk_sp3() AS
  5. CURSOR cur1 IS SELECT * FROM t1;
  6. TYPE udtt IS TABLE OF t1%ROWTYPE INDEX BY BINARY_INTEGER;
  7. udtt_t1 udtt;
  8. v_i INT := 0;
  9. BEGIN
  10. OPEN cur1;
  11. LOOP
  12. SELECT v_i;
  13. -- 因为fetch只会执行2次,因此第三次就可以退出了。
  14. EXIT WHEN v_i % @@select_bulk_into_batch > 1;
  15. FETCH cur1 BULK COLLECT INTO udtt_t1;
  16. FOR i IN udtt_t1.FIRST .. udtt_t1.LAST LOOP
  17. SELECT udtt_t1(i).a, udtt_t1(i).b;
  18. END LOOP;
  19. v_i := v_i + 1;
  20. END LOOP;
  21. CLOSE cur1;
  22. END; //
  23. greatsql> CALL bulk_sp3() //
  24. +------+
  25. | v_i |
  26. +------+
  27. | 0 |
  28. +------+
  29. 1 row in set (0.00 sec)
  30. +--------------+--------------+
  31. | udtt_t1(i).a | udtt_t1(i).b |
  32. +--------------+--------------+
  33. | 1 | row1 |
  34. +--------------+--------------+
  35. 1 row in set (0.00 sec)
  36. +--------------+--------------+
  37. | udtt_t1(i).a | udtt_t1(i).b |
  38. +--------------+--------------+
  39. | 2 | row2 |
  40. +--------------+--------------+
  41. 1 row in set (0.00 sec)
  42. +--------------+--------------+
  43. | udtt_t1(i).a | udtt_t1(i).b |
  44. +--------------+--------------+
  45. | 3 | row3 |
  46. +--------------+--------------+
  47. 1 row in set (0.00 sec)
  48. +------+
  49. | v_i |
  50. +------+
  51. | 1 |
  52. +------+
  53. 1 row in set (0.00 sec)
  54. +------+
  55. | v_i |
  56. +------+
  57. | 2 |
  58. +------+
  59. 1 row in set (0.00 sec)
  60. Query OK, 0 rows affected (0.00 sec)

更多关联用法:

问题反馈

联系我们

扫码关注微信公众号

greatsql-wx