Конкатенация типов данных CLOB в LOOP в PL / SQL - PullRequest
1 голос
/ 18 июня 2010

Я пытаюсь объединить сгустки в цикле PL / SQL, и он возвращает нулевое значение, в то время как при использовании DBMS_OUTPUT выводит значения цикла, а при выполнении каждого результата сгустков также выводится.

Система предназначена для выполнения уже сохраненного SQL в таблице на основе имени отчета, переданного в нее.Этот конкретный отчет имеет много названий отчетов;отсюда конкатенация каждого из отчетов.Передаваемыми аргументами являются имя отчета, версия отчета, в которой вы заинтересованы, тип разделителя, который вы хотите, и список аргументов для неизвестных в SQL, если таковые имеются.Есть также два основных типа SQL;1, которому необходимо заменить имя_таблицы на временное имя_таблицы, а другое, которому требуется идентификатор, добавляется к имени_таблицы в SQL.

, пожалуйста, найдите ниже код для функции REPREF1.

CREATE OR REPLACE FUNCTION REPREF1(P_VER       IN VARCHAR2 DEFAULT 'LATEST',
                                   P_SEPARATOR IN VARCHAR2 DEFAULT ', ',
                                   P_ARGLIST   IN VAR DEFAULT NULL) RETURN CLOB IS
  L_CLOB CLOB;
  FUNCTION GET_CLOB(P_REPNAM    IN VARCHAR2,
                    P_VER       IN VARCHAR2 DEFAULT 'LATEST',
                    P_SEPARATOR IN VARCHAR2 DEFAULT ', ',
                    P_ARGLIST   IN VAR DEFAULT NULL) RETURN CLOB IS
    ---------------------------------------------------------------------------------
    -- TITLE - GET_CLOB beta - b.0  DATE 2010Mar12
    --
    -- DESCRIPTION -  A function that return a report based on the report name put in
    --
    -- USAGE - select get_clob(p_repnam,p_ver, p_separator, var(varay(val_1,...val_n), varay(val_1,...val_n))) FROM dual
    -----------------------------------------------------------------------------------------------------------------------------
    V_SQL       VARCHAR2(32767);
    L_RESULT    CLOB;
    V_TITLE     VARCHAR2(4000);
    V_REPDATE   VARCHAR2(30);
    V_CNT       NUMBER(2);
    V_NUMARG    NUMBER(3);
    V_CDCRU     NUMBER(3);
    V_BCNT      NUMBER(3);
    V_NEWTABDAT VARCHAR2(30);
    V_NEWTABLIN VARCHAR2(30);
    L_COLLIST   VARAY;
    V_VER       VARCHAR2(6);
    N           PLS_INTEGER;
    V_CNTTAB    NUMBER(3);

    -- EXEC_SQL_CLOB  
    FUNCTION EXEC_SQL_CLOB(P_SQL       IN VARCHAR2,
                           P_NUMARG    IN NUMBER,
                           P_COLLIST   IN VARAY DEFAULT NULL,
                           P_ARGLIST   IN VARAY DEFAULT NULL,
                           P_SEPARATOR IN VARCHAR2 DEFAULT '') RETURN CLOB IS
      ------------------------------------------------------------------------------------------------------
      -- TITLE - EXEC_SQL_CLOB beta - b.0  DATE 2010Mar22
      --
      -- DESCRIPTION -  A function that returns a clob value after executing the sql query that is passed into it 
      --
      -- USAGE - select exec_sql_clob(p_sql, p_numarg, var(varay(val_1, val_2,...val_n), varay(val_1, val_2,...val_n))) FROM dual
      ---------------------------------------------------------------------------------------------------------------
      L_CUR       INTEGER DEFAULT DBMS_SQL.OPEN_CURSOR;
      L_STATUS    INTEGER;
      V_COL       VARCHAR2(4000);
      L_RESULT    CLOB;
      L_COLCNT    NUMBER DEFAULT 0;
      L_SEPARATOR VARCHAR2(10) DEFAULT '';
      V_NUMARG    NUMBER(3);

    BEGIN
      -- parse the query for the report
      DBMS_SQL.PARSE(L_CUR, P_SQL, DBMS_SQL.NATIVE);
      -- whilst it is not more than 255 per line
      FOR I IN 1 .. 255
      LOOP
        BEGIN
          -- define each column in the select list
          DBMS_SQL.DEFINE_COLUMN(L_CUR, I, V_COL, 2000);
          L_COLCNT := I;
        EXCEPTION
          WHEN OTHERS THEN
            IF (SQLCODE = -1007) THEN
              EXIT;
            ELSE
              RAISE;
            END IF;
        END;
      END LOOP;

      -- If query has no bind variables
      IF (P_ARGLIST IS NULL) THEN
        IF (P_NUMARG = 0) THEN
          -- Execute the query in the cursor
          L_STATUS := DBMS_SQL.EXECUTE(L_CUR);
          LOOP
            -- Exit loop when fetch is complete
            EXIT WHEN(DBMS_SQL.FETCH_ROWS(L_CUR) <= 0);
            L_SEPARATOR := '';
            FOR I IN 1 .. L_COLCNT
            LOOP
              DBMS_SQL.COLUMN_VALUE(L_CUR, I, V_COL);
              L_RESULT    := L_RESULT || L_SEPARATOR || V_COL;
              L_RESULT    := REPLACE(REPLACE(L_RESULT, CHR(13) || CHR(10), ' '), CHR(10), ' ');
              L_SEPARATOR := P_SEPARATOR;
            END LOOP;
            L_RESULT := L_RESULT || CHR(13);
          END LOOP;
        ELSE
          RAISE_APPLICATION_ERROR(-20011, ' INCORRECT NUMBER OF ARGUMENTS PASSED IN LIST ');
        END IF;
        -- Query has bind variables
      ELSE
        -- Check if the numarg passed is the same has stored in the table
        SELECT NUMARG
          INTO V_NUMARG
          FROM REPVER
         WHERE REPCODE = P_SQL;
        -- If number of arguments is greater than 0
        IF (V_NUMARG > 0) THEN
          -- Check if the number of arguments are the same
          IF (P_NUMARG = V_NUMARG) THEN
            -- Replace the bind variables in the query
            FOR J IN 1 .. P_ARGLIST.COUNT
            LOOP
              DBMS_SQL.BIND_VARIABLE(L_CUR, P_COLLIST(J), P_ARGLIST(J));
            END LOOP;
            -- Execute the query in the cursor
            L_STATUS := DBMS_SQL.EXECUTE(L_CUR);
            LOOP
              -- Exit loop when fetch is complete
              EXIT WHEN(DBMS_SQL.FETCH_ROWS(L_CUR) <= 0);
              L_SEPARATOR := '';
              FOR I IN 1 .. L_COLCNT
              LOOP
                DBMS_SQL.COLUMN_VALUE(L_CUR, I, V_COL);
                L_RESULT    := L_RESULT || L_SEPARATOR || V_COL;
                L_RESULT    := REPLACE(REPLACE(L_RESULT, CHR(13) || CHR(10), ' '), CHR(10), ' ');
                L_SEPARATOR := P_SEPARATOR;
              END LOOP;
              L_RESULT := L_RESULT || CHR(13);
            END LOOP;
          ELSE
            RAISE_APPLICATION_ERROR(-20011, ' INCORRECT NUMBER OF ARGUMENTS PASSED IN LIST ');
          END IF;
        ELSE
          -- If the number of argument is equal to 0
          IF (P_NUMARG = 0) THEN
            -- Execute the query in the cursor
            L_STATUS := DBMS_SQL.EXECUTE(L_CUR);
            LOOP
              -- Exit loop when fetch is complete
              EXIT WHEN(DBMS_SQL.FETCH_ROWS(L_CUR) <= 0);
              L_SEPARATOR := '';
              FOR I IN 1 .. L_COLCNT
              LOOP
                DBMS_SQL.COLUMN_VALUE(L_CUR, I, V_COL);
                L_RESULT    := L_RESULT || L_SEPARATOR || V_COL;
                L_RESULT    := REPLACE(REPLACE(L_RESULT, CHR(13) || CHR(10), ' '), CHR(10), ' ');
                L_SEPARATOR := P_SEPARATOR;
              END LOOP;
              L_RESULT := L_RESULT || CHR(13);
            END LOOP;
          ELSE
            RAISE_APPLICATION_ERROR(-20011, ' INCORRECT NUMBER OF ARGUMENTS PASSED IN LIST ');
          END IF;
        END IF;
      END IF;
      -- Close cursor
      DBMS_SQL.CLOSE_CURSOR(L_CUR);
      RETURN L_RESULT;
    END EXEC_SQL_CLOB;
  BEGIN
    -- Check if the version entered is null or latest
    IF (P_VER IS NULL)
       OR (UPPER(P_VER) = UPPER('LATEST')) THEN
      SELECT MAX(VER)
        INTO V_VER
        FROM REPORT B, REPVER R
       WHERE UPPER(REPNAM) = UPPER(P_REPNAM)
         AND B.REPREF = R.REPREF;
    ELSE
      V_VER := P_VER;
    END IF;

    -- Check if the repname and version entered exists
    SELECT COUNT(*)
      INTO V_CNT
      FROM REPORT B, REPVER R
     WHERE UPPER(REPNAM) = UPPER(P_REPNAM)
       AND VER = V_VER
       AND B.REPREF = R.REPREF;

    IF (V_CNT > 0) THEN
      -- Store the SQL statement, title and number of arguments of the report name passed.
      SELECT REPCODE, REPTITLE, NUMARG, COLLIST
        INTO V_SQL, V_TITLE, V_NUMARG, L_COLLIST
        FROM REPVER R, REPORT B
       WHERE UPPER(REPNAM) = UPPER(P_REPNAM)
         AND B.REPREF = R.REPREF
         AND VER = V_VER;

      V_REPDATE := TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI');

      L_RESULT := V_TITLE || ' (' || P_REPNAM || ' version ' || V_VER || ') generated ' || V_REPDATE || CHR(13) || CHR(13);

      -- Check for some specific type of queries
      SELECT COUNT(*)
        INTO V_CDCRU
        FROM REPVER R, REPORT B
       WHERE CTDDATA = 'Y'
         AND UPPER(REPNAM) = UPPER(P_REPNAM)
         AND B.REPREF = R.REPREF
         AND VER = V_VER;

      SELECT COUNT(*)
        INTO V_BCNT
        FROM REPVER R, BODCREPS B
       WHERE BENLIST = 'Y'
         AND UPPER(REPNAM) = UPPER(P_REPNAM)
         AND B.REPREF = R.REPREF
         AND VER = V_VER;

      IF (V_CDCRU > 0) THEN

        V_NEWTABDATA := 'CT_' || 'DAT_' || P_ARGLIST(1) (P_ARGLIST(1).FIRST);
        V_NEWTABLINK := 'CT_' || 'LIN_' || P_ARGLIST(1) (P_ARGLIST(1).FIRST);

        -- Check if the tables exist
        SELECT COUNT(*)
          INTO V_CNTTAB
          FROM ALL_TABLES
         WHERE TABLE_NAME = V_NEWTABDAT
            OR TABLE_NAME = V_NEWTABLIN
           AND OWNER = 'SCOTT';

        IF (V_CNTTAB > 0) THEN

          V_SQL := UPPER(V_SQL);
          V_SQL := REPLACE(V_SQL, 'CT_DAT_CRU', V_NEWTABDAT);
          V_SQL := REPLACE(V_SQL, 'CT_LIN_CRU', V_NEWTABLIN);

        ELSE
          V_SQL := 'SELECT ''THE TABLE NOT CREATED YET''
                              FROM DUAL';
        END IF;
      END IF;

      IF (V_BCNT > 0) THEN

        V_SQL := UPPER(V_SQL);
        V_SQL := REPLACE(V_SQL, 'LIST', P_ARGLIST(1) (P_ARGLIST(1).LAST));

      END IF;

      IF (P_ARGLIST IS NULL) THEN
        -- execute the query
        L_RESULT := L_RESULT || EXEC_SQL_CLOB(V_SQL, V_NUMARG, L_COLLIST, NULL, P_SEPARATOR);
      ELSE
        N := P_ARGLIST.COUNT;
        -- execute the query
        L_RESULT := L_RESULT || EXEC_SQL_CLOB(V_SQL, V_NUMARG, L_COLLIST, P_ARGLIST(N), P_SEPARATOR);
      END IF;
      RETURN L_RESULT;
    ELSE
      RAISE_APPLICATION_ERROR(-20012, P_REPNAM || ' or ' || P_VER || ' DOES NOT EXIST ');
    END IF;
  END GET_CLOB;
BEGIN
  FOR I IN (SELECT REPNAM
              FROM REPORT
             WHERE REPREF NOT IN ('R01', 'R02', 'R03', 'R04'))
  LOOP
    SELECT CONCAT_CLOB(GET_CLOB(I.REPNAM, P_VER, P_SEPARATOR, P_ARGLIST))
      INTO L_CLOB
      FROM DUAL;
    DBMS_OUTPUT.PUT_LINE(I.REPNAM);
    -- DBMS_OUTPUT.PUT_LINE (COUNT(i.REPNAM));
  END LOOP;
  RETURN L_CLOB;
END REPREF1;

/

Cheers, Tunde

Большое спасибо APC за то, что код выглядел лучше.@ Роберт, последний цикл в коде возвращает ноль даже с помощью агрегатной функции CONCAT_CLOB, которая объединяет сгустки.

FOR I IN (SELECT REPNAM
            FROM REPORT
           WHERE REPREF NOT IN ('R01', 'R02', 'R03', 'R04'))
LOOP
  SELECT CONCAT_CLOB(GET_CLOB(I.REPNAM, P_VER, P_SEPARATOR, P_ARGLIST))
    INTO L_CLOB
    FROM DUAL;
  DBMS_OUTPUT.PUT_LINE(I.REPNAM);
END LOOP;

, когда я пытаюсь это сделать,

FOR I IN (SELECT REPNAM
            FROM REPORT
           WHERE REPREF NOT IN ('R01', 'R02', 'R03', 'R04'))
LOOP
  L_CLOB := L_CLOB || CHR(13) || GET_CLOB(I.REPNAM, P_VER, P_SEPARATOR, P_ARGLIST);
  DBMS_OUTPUT.PUT_LINE(I.REPNAM);
END LOOP;

Это также дает ноль;но на этот раз вывод дБмс для репнам не завершен.

Ответы [ 2 ]

2 голосов
/ 23 июня 2010

Не знаю о вашем коде. Вот как это работает для меня: Всякий раз, когда я создаю функцию, возвращающую значение clob, я делаю это:

function foo return clob is
l_clob clob;
begin
      dbms_lob.createtemporary(lob_loc => l_lob, cache => true, dur => dbms_lob.call);
      ...
      return l_clob;
end;

При объединении значений в сгусток я использую функцию:

   procedure add_string_to_clob(p_lob    in out nocopy clob
                             ,p_string varchar2) is
   begin
      dbms_lob.writeappend(lob_loc => p_lob, amount => length(p_string), buffer => p_string);
   end;
1 голос
/ 06 декабря 2011

Вы должны использовать

dbms_lob.substr(your clob parameter,start position, length)

Например,

dbms_output('my clob value:' || dbms_lob.substr(your clob parameter,start position, length);

Но вы можете напечатать в строке максимум 4000 символов, затем вы можете использовать это в циклической функции для печати 4000 символов в каждой строке.

...