select 过程中有可变参数
select with variable parameter in the procedure
我正在尝试编写具有以下功能的过程。即,正在从架构中的 table 中查找记录。特别是,它是这些 table 中的一个 typepkstring 列。同时,我在同一个模式上有 composedtypes table,它有 pk 列。 pk 列包含来自上述 typepkstring 列的所有数字标识符。现在的问题是,在 typepkstring 中,我们还有一些键不在 tabel composedtypes 的 pk 列中。我必须搜索架构并将其与它们所在的 table 的名称一起写出来。
此时,我的程序如下所示:
create or replace PROCEDURE SIEROT
(i_table_name VARCHAR2)
is
CURSOR c is
SELECT DISTINCT i_table_name.TYPEPKSTRING
FROM i_table_name
LEFT OUTER JOIN COMPOSEDTYPES
ON i_table_name.TYPEPKSTRING=COMPOSEDTYPES.PK
WHERE COMPOSEDTYPES.PK IS NULL;
TYPE c_list IS TABLE of PRODUCTS.TYPEPKSTRING%type INDEX BY binary_integer;
TYPEPK_list c_list;
counter integer :=0;
BEGIN
FOR n IN c LOOP
counter := counter +1;
TYPEPK_list(counter) := n.TYPEPKSTRING;
dbms_output.put_line('TABLE: '||i_table_name||'('||counter||'):'||TYPEPK_list(counter));
END LOOP;
END;
并致电:
set serveroutput on
DECLARE
ind integer := 0;
BEGIN
FOR ind IN (select table_name from all_tab_columns where column_name='TYPEPKSTRING' AND table_name!='COMPOSEDTYPES')
LOOP
BEGIN
SIEROT(ind.table_name);
EXCEPTION
WHEN NO_DATA_FOUND THEN
null;
END;
END LOOP;
END;
这是我使用的第二种解决问题的方法,对我来说似乎更容易。第二个也没有功能,是基于使用数组类型的游标。
我的问题是:
调用当然可以正常工作,但是当我编译相同的过程时,出现以下错误:
Procedure SIEROT compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
5/7 PL/SQL: SQL Statement ignored
6/31 PL/SQL: ORA-00942: table or view does not exist
17/7 PL/SQL: Statement ignored
17/31 PLS-00364: loop index variable 'N' use is invalid
Errors: check compiler log
永久输入 table 名称的相同 select,我自己放置了 2 条符合任务条件的记录,工作正常:
SELECT DISTINCT TESTOWY.TYPEPKSTRING
FROM TESTOWY
LEFT OUTER JOIN COMPOSEDTYPES
ON TESTOWY.TYPEPKSTRING=COMPOSEDTYPES.PK
WHERE COMPOSEDTYPES.PK IS NULL;
并且对于 select 在过程中如此输入,它得到了预期的效果但是,如果它想搜索整个模式,我需要参数化源 table 的名称,不只是在特定的一个。上面提到的 select 中只有一个就足够了:
TABLE: TESTOWY(1):8790000000098
TABLE: TESTOWY(2):8790000000124
PL/SQL procedure successfully completed.
我真的没有力气做这个程序。写信告诉我如何改进它以使其发挥作用,同时满足您的意见。感谢任何提示或更正;)
您必须在此处使用动态 SQL(即 execute immediate
),因为 table 名称(作为参数传递)不能在查询中使用。按照你的说法,似乎SIEROT程序中的整个代码应该是dynamic.
这是一个基于 Scott 架构的示例(因为我没有您的 tables):
SQL> set serveroutput on
SQL> create or replace procedure sierot(i_table_name in varchar2)
2 is
3
4 l_str varchar2(2000);
5 l_str_2 varchar2(2000);
6 counter integer := 0;
7 begin
8 l_str := 'select distinct i.empno typepkstring from ' || i_table_name || ' i join dept d on d.deptno = i.deptno
9 where d.deptno = 10';
10
11 l_str_2 := 'declare
12 counter integer := 0;
13 type c_list is table of emp.empno%type index by binary_integer;
14 typepk_list c_list;
15 begin
16 for n in (' || l_str ||') loop
17 counter := counter + 1;
18 typepk_list(counter) := n.typepkstring;
19 dbms_output.put_line(TYPEPK_list(counter));
20 end loop;
21 end;';
22
23 execute immediate l_str_2;
24
25 end;
26 /
Procedure created.
SQL> exec sierot('emp');
7782
7839
7934
PL/SQL procedure successfully completed.
SQL>
您不能在查询中直接将参数值用作 table 名称 - 您需要动态构建 SELECT 语句,然后使用循环获取数据:
CREATE OR REPLACE PROCEDURE SIEROT(i_table_name VARCHAR2) IS
strSelect VARCHAR2(32767);
c SYS_REFCURSOR;
vTYPEPKSTRING PRODUCTS.TYPEPKSTRING%TYPE;
TYPE c_list IS TABLE of PRODUCTS.TYPEPKSTRING%type INDEX BY binary_integer;
TYPEPK_list c_list;
counter integer := 0;
BEGIN
strSelect := 'SELECT DISTINCT i.TYPEPKSTRING ' ||
' FROM ' || i_table_name || ' i ' ||
' LEFT OUTER JOIN COMPOSEDTYPES c ' ||
' ON i.TYPEPKSTRING = c.PK ' ||
' WHERE c.PK IS NULL';
OPEN c FOR strSelect;
FETCH c INTO vTYPEPKSTRING;
WHILE c%FOUND LOOP
counter := counter + 1;
TYPEPK_list(counter) := vTYPEPKSTRING;
dbms_output.put_line('TABLE: '||i_table_name||'('||counter||'):'||TYPEPK_list(counter));
FETCH c INTO vTYPEPKSTRING;
END LOOP;
CLOSE c;
EXCEPTION
WHEN OTHERS THEN
IF c%ISOPEN THEN
CLOSE c;
END IF;
END SIEROT;
祝你好运。
我正在尝试编写具有以下功能的过程。即,正在从架构中的 table 中查找记录。特别是,它是这些 table 中的一个 typepkstring 列。同时,我在同一个模式上有 composedtypes table,它有 pk 列。 pk 列包含来自上述 typepkstring 列的所有数字标识符。现在的问题是,在 typepkstring 中,我们还有一些键不在 tabel composedtypes 的 pk 列中。我必须搜索架构并将其与它们所在的 table 的名称一起写出来。
此时,我的程序如下所示:
create or replace PROCEDURE SIEROT
(i_table_name VARCHAR2)
is
CURSOR c is
SELECT DISTINCT i_table_name.TYPEPKSTRING
FROM i_table_name
LEFT OUTER JOIN COMPOSEDTYPES
ON i_table_name.TYPEPKSTRING=COMPOSEDTYPES.PK
WHERE COMPOSEDTYPES.PK IS NULL;
TYPE c_list IS TABLE of PRODUCTS.TYPEPKSTRING%type INDEX BY binary_integer;
TYPEPK_list c_list;
counter integer :=0;
BEGIN
FOR n IN c LOOP
counter := counter +1;
TYPEPK_list(counter) := n.TYPEPKSTRING;
dbms_output.put_line('TABLE: '||i_table_name||'('||counter||'):'||TYPEPK_list(counter));
END LOOP;
END;
并致电:
set serveroutput on
DECLARE
ind integer := 0;
BEGIN
FOR ind IN (select table_name from all_tab_columns where column_name='TYPEPKSTRING' AND table_name!='COMPOSEDTYPES')
LOOP
BEGIN
SIEROT(ind.table_name);
EXCEPTION
WHEN NO_DATA_FOUND THEN
null;
END;
END LOOP;
END;
这是我使用的第二种解决问题的方法,对我来说似乎更容易。第二个也没有功能,是基于使用数组类型的游标。 我的问题是: 调用当然可以正常工作,但是当我编译相同的过程时,出现以下错误:
Procedure SIEROT compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
5/7 PL/SQL: SQL Statement ignored
6/31 PL/SQL: ORA-00942: table or view does not exist
17/7 PL/SQL: Statement ignored
17/31 PLS-00364: loop index variable 'N' use is invalid
Errors: check compiler log
永久输入 table 名称的相同 select,我自己放置了 2 条符合任务条件的记录,工作正常:
SELECT DISTINCT TESTOWY.TYPEPKSTRING
FROM TESTOWY
LEFT OUTER JOIN COMPOSEDTYPES
ON TESTOWY.TYPEPKSTRING=COMPOSEDTYPES.PK
WHERE COMPOSEDTYPES.PK IS NULL;
并且对于 select 在过程中如此输入,它得到了预期的效果但是,如果它想搜索整个模式,我需要参数化源 table 的名称,不只是在特定的一个。上面提到的 select 中只有一个就足够了:
TABLE: TESTOWY(1):8790000000098
TABLE: TESTOWY(2):8790000000124
PL/SQL procedure successfully completed.
我真的没有力气做这个程序。写信告诉我如何改进它以使其发挥作用,同时满足您的意见。感谢任何提示或更正;)
您必须在此处使用动态 SQL(即 execute immediate
),因为 table 名称(作为参数传递)不能在查询中使用。按照你的说法,似乎SIEROT程序中的整个代码应该是dynamic.
这是一个基于 Scott 架构的示例(因为我没有您的 tables):
SQL> set serveroutput on
SQL> create or replace procedure sierot(i_table_name in varchar2)
2 is
3
4 l_str varchar2(2000);
5 l_str_2 varchar2(2000);
6 counter integer := 0;
7 begin
8 l_str := 'select distinct i.empno typepkstring from ' || i_table_name || ' i join dept d on d.deptno = i.deptno
9 where d.deptno = 10';
10
11 l_str_2 := 'declare
12 counter integer := 0;
13 type c_list is table of emp.empno%type index by binary_integer;
14 typepk_list c_list;
15 begin
16 for n in (' || l_str ||') loop
17 counter := counter + 1;
18 typepk_list(counter) := n.typepkstring;
19 dbms_output.put_line(TYPEPK_list(counter));
20 end loop;
21 end;';
22
23 execute immediate l_str_2;
24
25 end;
26 /
Procedure created.
SQL> exec sierot('emp');
7782
7839
7934
PL/SQL procedure successfully completed.
SQL>
您不能在查询中直接将参数值用作 table 名称 - 您需要动态构建 SELECT 语句,然后使用循环获取数据:
CREATE OR REPLACE PROCEDURE SIEROT(i_table_name VARCHAR2) IS
strSelect VARCHAR2(32767);
c SYS_REFCURSOR;
vTYPEPKSTRING PRODUCTS.TYPEPKSTRING%TYPE;
TYPE c_list IS TABLE of PRODUCTS.TYPEPKSTRING%type INDEX BY binary_integer;
TYPEPK_list c_list;
counter integer := 0;
BEGIN
strSelect := 'SELECT DISTINCT i.TYPEPKSTRING ' ||
' FROM ' || i_table_name || ' i ' ||
' LEFT OUTER JOIN COMPOSEDTYPES c ' ||
' ON i.TYPEPKSTRING = c.PK ' ||
' WHERE c.PK IS NULL';
OPEN c FOR strSelect;
FETCH c INTO vTYPEPKSTRING;
WHILE c%FOUND LOOP
counter := counter + 1;
TYPEPK_list(counter) := vTYPEPKSTRING;
dbms_output.put_line('TABLE: '||i_table_name||'('||counter||'):'||TYPEPK_list(counter));
FETCH c INTO vTYPEPKSTRING;
END LOOP;
CLOSE c;
EXCEPTION
WHEN OTHERS THEN
IF c%ISOPEN THEN
CLOSE c;
END IF;
END SIEROT;
祝你好运。