1

Curent situation

Currently I have this PL-SQL script with almost fifty words "hard-coded":

DECLARE
categoryToSearch VARCHAR2(16);
BEGIN
categoryToSearch := 'my_category';
FOR my_object IN (SELECT my_field FROM my_schema.my_table
                  WHERE other_field = categoryToSearch
                  AND my_field IN ('WORD_1', 'WORD_2', 'WORD_3', 'WORD_4', 'WORD_5', 'WORD_6')
                  GROUP BY my_field ORDER BY my_field)
LOOP
    -- <loop code>
END LOOP;
-- <code>

This is working (yes I only display 6 words for the example)


What I want

But now I would like to change dynamically this list of words, so I implemented the following:

DECLARE
categoryToSearch VARCHAR2(16);
listOfWords      VARCHAR2(512);
BEGIN
categoryToSearch := 'my_category';
listOfWords      := '''WORD_1'', ''WORD_2'', ''WORD_3'', ''WORD_4'', ''WORD_5'', ''WORD_6''';
FOR my_object IN (SELECT my_field FROM my_schema.my_table
                  WHERE other_field = categoryToSearch
                  AND my_field IN ( listOfWords )        -- I changed this, putting a variable instead of a hard-coded list
                  GROUP BY my_field ORDER BY my_field)
LOOP
    -- <loop code>
END LOOP;
-- <code>

This "compiles" (ho ho ho), I mean no SQL errors. But strange issue, this code do NOT return any rows compare to the first one, like listOfWord became empty, different or badly interpreted, I don't know why.

Questions:

  • Why my new version is not working ?
  • Why it is working with categoryToSearch and NOT with listOfWords ?
  • When using IN ( listOfWord ), could it be any issue with the quotes ? (=> assignment)
  • Am I doing correctly the binding ? (eg. using : or @ ?)
  • Can I use a USING to bind ? i try but nothing work

I tried:

FOR my_object IN (SELECT my_column FROM schemaToAnalyze
                  WHERE other_field = categoryToSearch
                  AND my_field IN ( :my_list )
                  GROUP BY my_field ORDER BY my_field) USING listOfWords

even

FOR my_object IN ('SELECT my_column FROM schemaToAnalyze
                  WHERE other_field = categoryToSearch
                  AND my_field IN (' || listOfWords || ')
                  GROUP BY my_field ORDER BY my_field')

and

FOR my_object IN (EXECUTE IMMEDIATE 'SELECT my_column FROM schemaToAnalyze
                  WHERE other_field = categoryToSearch
                  AND my_field IN (' || listOfWords || ')
                  GROUP BY my_field ORDER BY my_field')

and even:

FOR my_object IN (SELECT my_column FROM schemaToAnalyze
                  WHERE other_field = categoryToSearch
                  AND my_field IN ( @listOfWords )
                  GROUP BY my_field ORDER BY my_field)
user12642493
  • 89
  • 1
  • 9
  • The first PL/SQL block you posted does not work. You are selecting `my_column` but grouping by `my_field`, so you will get a `not a GROUP BY expression` error. – Luke Woodward Feb 23 '21 at 19:34
  • Does this answer your question? [How do I check for a IN condition against a dynamic list in Oracle?](https://stackoverflow.com/questions/3462011/how-do-i-check-for-a-in-condition-against-a-dynamic-list-in-oracle) – Gary_W Feb 23 '21 at 19:36
  • @LukeWoodward : Thanks spotting that error, i change it – user12642493 Feb 23 '21 at 19:42
  • `FROM schemaToAnalyze` also won't work in your original version, unless you're using dynamic SQL - which you haven't shown. Anyway, collections are the answer, as shown in the linked question. – Alex Poole Feb 23 '21 at 19:53
  • @Gary_W : I tried the collection, but I cannot perform any "create or replace" since our DBA does not allow it. Or is there any other way to create a temp table with few rights ? – user12642493 Feb 23 '21 at 20:03
  • @AlexPoole : the exact query is: `SELECT table_name FROM all_tab_partitions WHERE table_owner = aSchemaName AND table_owner NOT LIKE '%_T' AND table_name IN ( SELECT table_name FROM all_tab_partitions WHERE table_name IN (aTablesToProcessText) ) GROUP BY table_name ORDER BY table_name` and indeed the variable is aSchemaName not for the name of the table. I thought it will be the same, so I will change this – user12642493 Feb 23 '21 at 20:05

3 Answers3

0

I tried the collection, but I cannot perform any "create or replace" since our DBA does not allow it.

You can use a built-in collection type, such as odcivarchar2list:

DECLARE
schemaToAnalyze  VARCHAR2(16);
categoryToSearch VARCHAR2(16);
listOfWords      SYS.ODCIVARCHAR2LIST;
BEGIN
categoryToSearch := 'my_category';
--schemaToAnalyze  := 'my_schema.my_table';
listOfWords      := SYS.ODCIVARCHAR2LIST('WORD_1', 'WORD_2', 'WORD_3', 'WORD_4', 'WORD_5', 'WORD_6');
FOR my_object IN (SELECT my_field FROM my_table -- schemaToAnalyze
                  WHERE other_field = categoryToSearch
                  AND my_field IN ( SELECT * FROM TABLE(listOfWords) )
                  GROUP BY my_field ORDER BY my_field)
LOOP
    dbms_output.put_line(my_object.my_field);
END LOOP;
END;
/

db<>fiddle

Alex Poole
  • 183,384
  • 11
  • 179
  • 318
0

You can reproduce the second attempt, which has variable concatenation, through use of SYS_REFCURSOR while keeping the current local variable (listOfWords) within a stored function or procedure such as

CREATE OR REPLACE FUNCTION Fn_Analyze_Schema RETURN SYS_REFCURSOR IS 
  v_recordset SYS_REFCURSOR; 
  v_sql       VARCHAR2(32767);
  listOfWords VARCHAR2(32767) := '''WORD_1'',''WORD_2'',''WORD_3'',....';
BEGIN
  v_sql := 'SELECT my_column 
              FROM schemaToAnalyze
             WHERE other_field = categoryToSearch
               AND my_field IN ('||listOfWords||')
             GROUP BY my_field 
             ORDER BY my_field';

  OPEN v_recordset FOR v_sql;
  RETURN v_recordset;
END;
/

Then call the following code from SQL Developer's command line

VAR rc REFCURSOR
EXEC :rc := Fn_Analyze_Schema;
PRINT rc
Barbaros Özhan
  • 59,113
  • 10
  • 31
  • 55
  • Maybe it is solution that way works, but I do not have rights to test it: – user12642493 Feb 23 '21 at 20:34
  • `Error report - ORA-01031: insufficient privileges 01031. 00000 - "insufficient privileges" *Cause: An attempt was made to perform a database operation without the necessary privileges. *Action: Ask your database administrator or designated security administrator to grant you the necessary privileges` – user12642493 Feb 23 '21 at 20:34
  • Hi @user12642493 , the message seems explanatory that just consult your DBA, most probably ask h[er|im] to grant you `create function` privilege. – Barbaros Özhan Feb 25 '21 at 12:18
-1

you can try to remove the double claws on your variable assignment listOfwords

  • I tried this: `listOfWords := 'WORD_1, WORD_2, WORD_3, WORD_4, WORD_5, WORD_6';` Didn't worked (same, the query returns nothing) – user12642493 Feb 23 '21 at 19:16
  • Either way you're trying to match a single string, which happens to contain commas, not a set of individual strings. The `IN (listOfWords)` is the same as `= listOfWords`. – Alex Poole Feb 23 '21 at 19:54