select with variable parameter in the procedure

走远了吗. 提交于 2020-01-05 04:22:28

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!