问题
I am trying to write a procedure with the following functionality. Namely, is looking for records from the tables in the schema. In particular, it is a typepkstring column in these tables. At the same time, I have the composedtypes table on the same schema, which has the column pk. The pk column contains all number identifiers from the aforementioned typepkstring column. And now the problem is that in typepkstring we have additionally keys that are not in the column pk in tabel composedtypes. And I have to search the schema and write it out together with the name of the table in which they are located.
at this point, my procedure looks as follows:
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;
and calling:
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;
this is the second approach to the problem I used, it seemed easier to me. The second one, also not functional, was based on cursors using the array type. My problem is: calling certainly works fine, but when I compile the same procedure I get the following error:
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
Same select for permanently entered table names, where I have put 2 records that meet the conditions of the task myself, works correctly:
SELECT DISTINCT TESTOWY.TYPEPKSTRING
FROM TESTOWY
LEFT OUTER JOIN COMPOSEDTYPES
ON TESTOWY.TYPEPKSTRING=COMPOSEDTYPES.PK
WHERE COMPOSEDTYPES.PK IS NULL;
and for select so typed in the procedure, it gets the intended effect but, I need to parameterize the name of the source table if it wants to search all of the whole schema, not just on specific one. Only one of the abovementioned selects would be sufficient for one particular:
TABLE: TESTOWY(1):8790000000098
TABLE: TESTOWY(2):8790000000124
PL/SQL procedure successfully completed.
I really do not have the strength for this procedure. Write me how to improve it to work but also fulfill your opinion. Thanks for any hints or corrections;)
回答1:
You can't use the value of a parameter as a table name in a query directly - you'll need to build your SELECT statement dynamically and then use a loop to fetch the data:
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;
Best of luck.
回答2:
You'll have to use dynamic SQL (i.e. execute immediate
) here, as table name (passed as a parameter) can't be used in a query. The way you put it, it seems that the whole code in SIEROT procedure should be dynamic.
Here's an example based on Scott's schema (as I don't have your 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>
来源:https://stackoverflow.com/questions/52204042/select-with-variable-parameter-in-the-procedure