【问题标题】:Native Dynamic SQL DDL statements not executing with bind variables in WHERE clause未使用 WHERE 子句中的绑定变量执行本机动态 SQL DDL 语句
【发布时间】:2015-02-21 10:37:35
【问题描述】:

我正在练习动态 SQL 和过程,以便为每周、每天和每月的仪表板实现一些脚本。这些仪表板要求我们创建表,因此我决定坚持使用动态 SQL。 在练习这些时,我遇到了一些错误,为了模拟错误,我创建了以下表格并复制了程序。

1。生成 EMP 表

CREATE TABLE EMP
(EMPNO NUMERIC(4) NOT NULL,
ENAME VARCHAR(10),
JOB VARCHAR(9),
MGR NUMERIC(4),
HIREDATE DATE,
SAL NUMERIC(7, 2),
COMM NUMERIC(7, 2),
DEPTNO NUMERIC(2));

INSERT INTO EMP VALUES
(7369, 'SMITH', 'CLERK', 7902, '17-DEC-1980', 800, NULL, 20);
INSERT INTO EMP VALUES
(7499, 'ALLEN', 'SALESMAN', 7698, '20-FEB-1981', 1600, 300, 30);
INSERT INTO EMP VALUES
(7521, 'WARD', 'SALESMAN', 7698, '22-FEB-1981', 1250, 500, 30);
INSERT INTO EMP VALUES
(7566, 'JONES', 'MANAGER', 7839, '2-APR-1981', 2975, NULL, 20);
INSERT INTO EMP VALUES
(7654, 'MARTIN', 'SALESMAN', 7698, '28-SEP-1981', 1250, 1400, 30);
INSERT INTO EMP VALUES
(7698, 'BLAKE', 'MANAGER', 7839, '1-MAY-1981', 2850, NULL, 30);
INSERT INTO EMP VALUES
(7782, 'CLARK', 'MANAGER', 7839, '9-JUN-1981', 2450, NULL, 10);
INSERT INTO EMP VALUES
(7788, 'SCOTT', 'ANALYST', 7566, '09-DEC-1982', 3000, NULL, 20);
INSERT INTO EMP VALUES
(7839, 'KING', 'PRESIDENT', NULL, '17-NOV-1981', 5000, NULL, 10);
INSERT INTO EMP VALUES
(7844, 'TURNER', 'SALESMAN', 7698, '8-SEP-1981', 1500, 0, 30);
INSERT INTO EMP VALUES
(7876, 'ADAMS', 'CLERK', 7788, '12-JAN-1983', 1100, NULL, 20);
INSERT INTO EMP VALUES
(7900, 'JAMES', 'CLERK', 7698, '3-DEC-1981', 950, NULL, 30);
INSERT INTO EMP VALUES
(7902, 'FORD', 'ANALYST', 7566, '3-DEC-1981', 3000, NULL, 20);
INSERT INTO EMP VALUES
(7934, 'MILLER', 'CLERK', 7782, '23-JAN-1982', 1300, NULL, 10);

2。生成 EmpSalary 表

CREATE TABLE empSalary
(ename varchar(20),
salary number
);


INSERT INTO empSalary VALUES ('SMITH', 2000);
INSERT INTO empSalary VALUES ('WARD', 300);
COMMIT;

以下过程很好

---- 制定程序 - 尝试 1

CREATE OR REPLACE PROCEDURE getData(dataType IN VARCHAR2)
IS
  newTbl VARCHAR2(20);
  sqlQuery  VARCHAR2(100);
  empName VARCHAR2(20) := 'SMITH';
BEGIN
  IF dataType = 'Weekly' THEN
      newTbl := 'empTblWeekly'||TO_CHAR(SYSDATE, 'ddmon');
      sqlQuery := 'CREATE TABLE '||newTbl||' as SELECT * FROM emp';
      EXECUTE IMMEDIATE sqlQuery;
  ELSIF dataType = 'Daily' THEN
      newTbl := 'empTblDaily'||TO_CHAR(SYSDATE, 'ddmon');
      sqlQuery := 'CREATE TABLE '||newTbl||' as SELECT * FROM empSalary';
      EXECUTE IMMEDIATE sqlQuery;
  ELSIF dataType = 'Monthly' THEN
      newTbl := 'empTblMonthly'||TO_CHAR(SYSDATE, 'ddmon');
      sqlQuery := 'CREATE TABLE '||newTbl||' as SELECT * FROM emp WHERE ENAME = ''SMITH''';
      EXECUTE IMMEDIATE sqlQuery;
  END IF;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
  DBMS_OUTPUT.PUT_LINE('No data found!');
  COMMIT;
END;

BEGIN
getData('Monthly');
END;

SELECT *
FROM empTblMonthly21Feb;

以下 2 个公式返回错误:

---- Formulating a Procedure  - Try 2

CREATE OR REPLACE PROCEDURE getData(dataType IN VARCHAR2)
IS
  newTbl VARCHAR2(20);
  sqlQuery  VARCHAR2(100);
  empName VARCHAR2(20) := 'SMITH';
BEGIN
  IF dataType = 'Weekly' THEN
      newTbl := 'empTblWeekly'||TO_CHAR(SYSDATE, 'ddmon');
      sqlQuery := 'CREATE TABLE '||newTbl||' as SELECT * FROM emp';
      EXECUTE IMMEDIATE sqlQuery;
  ELSIF dataType = 'Daily' THEN
      newTbl := 'empTblDaily'||TO_CHAR(SYSDATE, 'ddmon');
      sqlQuery := 'CREATE TABLE '||newTbl||' as SELECT * FROM empSalary';
      EXECUTE IMMEDIATE sqlQuery;
  ELSIF dataType = 'Monthly' THEN
      newTbl := 'empTblMonthly'||TO_CHAR(SYSDATE, 'ddmon');
      sqlQuery := 'CREATE TABLE '||newTbl||' as SELECT * FROM emp WHERE ENAME = :empName';
      EXECUTE IMMEDIATE sqlQuery USING empName;
  END IF;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
  DBMS_OUTPUT.PUT_LINE('No data found!');
  COMMIT;
END;

    BEGIN
    getData('Monthly');
    END;

    SELECT *
    FROM empTblMonthly21Feb;

---ORA-01027: bind variables not allowed for data definition operations ORA-06512: at "SYS.GETDATA", line 18 ORA-06512: at line 2


---- Formulating a Procedure  - Try 3

CREATE OR REPLACE PROCEDURE getData(dataType IN VARCHAR2)
IS
  newTbl VARCHAR2(20);
  sqlQuery  VARCHAR2(100);
  empName VARCHAR2(20) := 'SMITH';
BEGIN
  IF dataType = 'Weekly' THEN
      newTbl := 'empTblWeekly'||TO_CHAR(SYSDATE, 'ddmon');
      sqlQuery := 'CREATE TABLE '||newTbl||' as SELECT * FROM emp';
      EXECUTE IMMEDIATE sqlQuery;
  ELSIF dataType = 'Daily' THEN
      newTbl := 'empTblDaily'||TO_CHAR(SYSDATE, 'ddmon');
      sqlQuery := 'CREATE TABLE '||newTbl||' as SELECT * FROM empSalary';
      EXECUTE IMMEDIATE sqlQuery;
  ELSIF dataType = 'Monthly' THEN
      newTbl := 'empTblMonthly'||TO_CHAR(SYSDATE, 'ddmon');
      sqlQuery := 'CREATE TABLE '||newTbl||' as SELECT * FROM emp WHERE ENAME ='||empName;
      EXECUTE IMMEDIATE sqlQuery;
  END IF;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
  DBMS_OUTPUT.PUT_LINE('No data found!');
  COMMIT;
END;

    BEGIN
    getData('Monthly');
    END;

    SELECT *
    FROM empTblMonthly21Feb;

---ORA-00904: "SMITH": invalid identifier ORA-06512: at "SYS.GETDATA", line 18 ORA-06512: at line 2

但我无法理解为什么会出现错误,因为在第二次尝试中,我没有使用绑定变量作为表名,而在第三次尝试中,我只是连接了一个变量...

感谢您的帮助...

【问题讨论】:

  • 我认为错误信息很清楚:bind variables not allowed for data definition operations (i.e. DDL Statements)。这主要是因为 Oracle 有意地定义了这一点。无论如何,动态创建表是一个非常糟糕的主意。您还有许多其他可能性来满足您的要求,例如分区。
  • 在这种情况下,它听起来更像是一个Materialized View,甚至是一个简单的VIEW,由于视图不占用任何空间(至少几乎所有),因此创建数百个视图并不重要根据您的需要。
  • 我认为第三次尝试灵魂工作,但在字符串周围加上单引号。尝试:...其中 ENAME = ''' ||员工姓名 || ''';
  • EXECUTE IMMEDIATE sqlQuery; 永远不会引发任何NO_DATA_FOUND 异常,因为您不创建SELECT,而是创建CREATE TABLE 声明。你为什么要发COMMIT
  • 无论如何,每个 DDL 都会进行隐式 COMMIT,因此没用。如果只在异常情况下而不是在正常执行后才这样做,那就“更没用了”。

标签: sql oracle stored-procedures


【解决方案1】:

您的第三次尝试会成功,但您忘记了 sql 语句中的单引号(围绕 ename 变量)。尝试类似:

declare
  l_tabname varchar2(100) := 'MY_TAB1';
  l_name varchar2(100) := 'SMITH';
  l_sql varchar2(1000);
begin
  l_sql := 'create table ' || l_tabname || ' as select * from emp where ename = ''' || l_name || '''';
  execute immediate l_sql;
end;

没有使用绑定变量,但它仍然使用变量创建表。

【讨论】:

  • 谢谢,这行得通。但是一个问题:为什么我们必须添加像'''这样的引号|| l_name || '''';我只会添加'' || l_name || '';... 我知道如果我们想在引文中包含引文,我们会使用 2 个引号 ''SMITH'',但我不知道您的建议...
  • 它只是转义了单引号。请记住,如果要在单引号字符串中使用单引号,则需要两个连续的引号。
  • 另一个引号是结束被引用的字符串。大多数 IDE(如 Toad 或 Sql Developer)都会像上面的 SO 那样为代码着色,因此您可以查看是否需要另一个单引号来结束字符串。
猜你喜欢
  • 2014-10-18
  • 2014-02-16
  • 1970-01-01
  • 2013-06-14
  • 1970-01-01
  • 1970-01-01
  • 2020-09-27
  • 1970-01-01
  • 2011-01-02
相关资源
最近更新 更多