
# 执行动态查询语句
介绍执行动态查询语句。DWS提供两种方式：使用EXECUTE IMMEDIATE、OPEN FOR实现动态查询。前者通过动态执行SELECT语句，后者结合了游标的使用。当需要将查询的结果保存在一个数据集用于提取时，可使用OPEN FOR实现动态查询。
#### EXECUTE IMMEDIATE
语法图请参见[图1]。
图1EXECUTE IMMEDIATE dynamic_select_clause::=   
![](https://support.huaweicloud.com/devg-dws/figure/zh-cn_image_0000001764651252.png "点击放大")
using_clause子句的语法图参见[图2]。
图2using_clause-1   
![](https://support.huaweicloud.com/devg-dws/figure/zh-cn_image_0000001811610645.png "点击放大")
对以上语法格式的解释如下：
- define_variable，用于指定存放单行查询结果的变量。
- USING IN bind_argument，用于指定存放传递给动态SQL值的变量，即在dynamic_select_string中存在占位符时使用。
- USING OUT bind_argument，用于指定存放动态SQL返回值的变量。
  ![](https://support.huaweicloud.com/devg-dws/public_sys-resources/notice_3.0-zh-cn.png)
  - 查询语句中，into和out不能同时存在；
  
  - 占位符命名以":"开始，后面可跟数字、字符或字符串，与USING子句的bind_argument一一对应；
  
  - bind_argument只能是值、变量或表达式，不能是表名、列名、数据类型等数据库对象，即不支持使用bind_argument为动态SQL语句传递模式对象。如果存储过程需要通过声明参数传递数据库对象来构造动态SQL语句（常见于执行DDL语句时），建议采用连接运算符"\|\|"拼接dynamic_select_clause；
  
  - 动态PL/SQL块允许出现重复的占位符，即相同占位符只能与USING子句的一个bind_argument按位置对应。
    
**示例**
```
--从动态语句检索值（INTO 子句）：
DECLARE
   staff_count  VARCHAR2(20);
BEGIN
   EXECUTE IMMEDIATE 'select count(*) from staffs'
      INTO staff_count;
   dbms_output.put_line(staff_count);
END;
/
--传递并检索值（INTO子句用在USING子句前）：
CREATE OR REPLACE PROCEDURE dynamic_proc
AS
   staff_id     NUMBER(6) := 200;
   first_name   VARCHAR2(20);
   salary       NUMBER(8,2);
BEGIN
   EXECUTE IMMEDIATE 'select first_name, salary from staffs where staff_id = :1'
       INTO first_name, salary
       USING IN staff_id;
   dbms_output.put_line(first_name || ' ' || salary);
END;
/
--调用存储过程
CALL dynamic_proc();
--删除存储过程
DROP PROCEDURE dynamic_proc;
```
#### OPEN FOR
动态查询语句还可以使用OPEN FOR打开动态游标来执行。
语法参见[图3]。
图3open_for::=   
![](https://support.huaweicloud.com/devg-dws/figure/zh-cn_image_0000001764651248.png "点击放大")
参数说明：
- cursor_name：要打开的游标名。
- dynamic_string：动态查询语句。
- USING value：在dynamic_string中存在占位符时使用。
游标的使用请参考[DWS存储过程游标](https://support.huaweicloud.com/devg-dws/dws_04_0545.html)。
**示例**
```
DECLARE
    name          VARCHAR2(20);
    phone_number  VARCHAR2(20);
    salary        NUMBER(8,2);
    sqlstr        VARCHAR2(1024);
    TYPE app_ref_cur_type IS REF CURSOR;  --定义游标类型
    my_cur app_ref_cur_type;  --定义游标变量
    
BEGIN
    sqlstr := 'select first_name,phone_number,salary from staffs
         where section_id = :1';
    OPEN my_cur FOR sqlstr USING '30';  --打开游标, using是可选的
    FETCH my_cur INTO name, phone_number, salary; --获取数据
    WHILE my_cur%FOUND LOOP
          dbms_output.put_line(name||'#'||phone_number||'#'||salary);
          FETCH my_cur INTO name, phone_number, salary;
    END LOOP;
    CLOSE my_cur;   --关闭游标
END;
/
```
