Определите входной параметр CLOB для функции Oracle (ИЛИ Определите функцию с входным параметром CLOB) - PullRequest
0 голосов
/ 30 мая 2020

Я собираюсь запустить блок кода, как показано ниже:

CREATE OR REPLACE FUNCTION func_name (START_DATE NUMBER,END_DATE NUMBER, NAME clob)
                     .
                     .
                     .
        select * from table_name
        where name_desc in NAME
                     .
                     .
                     .
 END;

В котором его цель - создать функцию, одним из входных аргументов которой является тип данных CLOB. Но, выполнив свой код, я получаю следующую ошибку:

ORA-01704: слишком длинный строковый литерал

Я искал в inte rnet, а также среди вопросов о переполнении стека но это не имело никаких последствий.

Не могли бы вы мне помочь с этой проблемой?

1 Ответ

0 голосов
/ 17 июля 2020

Мне кажется, я понимаю, чего вы пытаетесь достичь. Согласно комментариям, вы неправильно используете IN. IN ожидает список литералов или список значений от select, но ваше значение CLOB не является ни тем, ни другим, это просто длинная строка, которую необходимо обработать, прежде чем вы сможете использовать ее в SELECT, как вы упомянули в комментариях.

Для обработки вашего CLOB со списком имен, разделенных ,, вы можете найти первую запятую в CLOB и извлечь значение из начала CLOB, пока этот первый разделитель и найденное значение не будут помещены в коллекцию (разделитель удаляется из c и значение обрезано, это может быть необязательным, поскольку я не уверен, как именно выглядит ваш ввод). Затем вы удаляете найденное значение из начала CLOB и повторяете, пока в этом CLOB не останется ничего для обработки. Если у вас есть список значений в коллекции, вы можете использовать его как SELECT в исходном SELECT.

Попробуйте этот пример:

CREATE TABLE table_name (
  name_desc VARCHAR2(250) NOT NULL
);

INSERT INTO table_name (name_desc)
VALUES ('Lorem');
INSERT INTO table_name (name_desc)
VALUES ('ipsum');
INSERT INTO table_name (name_desc)
VALUES ('test');

COMMIT;

CREATE OR REPLACE TYPE name_list_tabt IS TABLE OF VARCHAR2(4000);
/

CREATE OR REPLACE PROCEDURE func_name(p_start_date NUMBER,
                                      p_end_date   NUMBER,
                                      p_name       CLOB) IS
  v_delimiter VARCHAR2(1) := ',';
  v_name CLOB := p_name;
  v_delimiter_pos NUMBER;
  v_name_value VARCHAR2(4000);
  v_name_list name_list_tabt := name_list_tabt();
BEGIN

  -- OTHER CODE ABOVE ...

  LOOP
    -- Get position of delimiter
    v_delimiter_pos := dbms_lob.instr(v_name, v_delimiter, 1, 1);
    -- If no comma is found we get rest of the CLOB for last name, if there is no more CLOB to process this will return 0
    IF v_delimiter_pos = 0
    THEN
      v_delimiter_pos := dbms_lob.getlength(v_name);
    END IF;
    -- Get next name based on delimiter position, can cause error if single name is over 4000 bytes long
    v_name_value := dbms_lob.substr(v_name, v_delimiter_pos, 1);
    -- Next code will remove found name from CLOB start
    v_name := regexp_replace(v_name, v_name_value, NULL, 1, 1);
    -- If we reached the end of CLOB, exit
    IF v_delimiter_pos = 0
    THEN
      EXIT;
    END IF;
    -- Add new name to collection if it is not empty
    IF TRIM(REPLACE(v_name_value, v_delimiter)) IS NOT NULL
    THEN
      v_name_list.extend();
      v_name_list(v_name_list.count) := TRIM(REPLACE(v_name_value, v_delimiter));
    END IF;
  END LOOP;
  -- Your select in for loop just to make this code working, adjust as you need
  FOR i IN (SELECT *
              FROM table_name
             WHERE name_desc IN (SELECT /*+ dynamic_sampling(t 2) */
                                  column_value
                                   FROM TABLE(v_name_list) t))
  LOOP
    dbms_output.put_line(i.name_desc); -- Just some test output
  END LOOP;

  -- OTHER CODE BELOW ...

END;
/

BEGIN
  -- Example with different, even possibly incorrect values
  func_name(p_start_date => 1,
            p_end_date   => 2,
            p_name       => 'Lorem,ipsum,dolor,sit,amet,consectetur, 
 ,,adipiscing,elit,Etiam,interdum,ligula,    ,     ,');
  -- Based on table values and CLOB here output should be "Lorem" and "ipsum"
END;
/
...