oracle PL/SQL 中 LOOP 中 CLOB 数据类型的串联

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3068306/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 20:51:18  来源:igfitidea点击:

Concatenation of CLOB datatypes in a LOOP in PL/SQL

oracleloopsplsqlclob

提问by Tunde

I am trying to concatenate clobs in a PL/SQL loop and it has been returning null whilst when using DBMS_OUTPUT prints out the loop values and when executing each result of the clobs gives an output as well.

我试图在 PL/SQL 循环中连接 clobs 并且它一直返回 null 而当使用 DBMS_OUTPUT 打印出循环值并且在执行 clobs 的每个结果时也会给出输出。

The system is meant to execute an already stored SQL in a table based on the report name passed into it. This particular report has many report names; hence the concatenation of each of the reports. The arguments passed are the report name, version of the report you're interested in, the kind of separator you want, and an argument list for the unknowns in the SQL if any. There are also two main types of SQL; 1 that needs the table_name be replaced with a temp table_name and another that needs an ID be appended to a table_name in the SQL.

该系统旨在根据传入的报告名称执行表中已存储的 SQL。这个特定的报告有很多报告名称;因此,每个报告的串联。传递的参数是报告名称、您感兴趣的报告版本、所需的分隔符类型以及 SQL 中未知数的参数列表(如果有)。还有两种主要的 SQL 类型;1 需要将 table_name 替换为临时 table_name,另一个需要将 ID 附加到 SQL 中的 table_name。

please find below the code for the REPREF1 function.

请在下面找到 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

干杯,通德

Many thanks APC for making the code look better. @Robert, the last loop in the code returns null even with the CONCAT_CLOB aggregate function that concatenates clobs.

非常感谢 APC 让代码看起来更好。@Robert,即使使用连接 clobs 的 CONCAT_CLOB 聚合函数,代码中的最后一个循环也返回 null。

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;

when I try this,

当我尝试这个时

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;

It also gives null; but this time the dbms output for the repnam are not complete.

它也给 null; 但这一次 repnam 的 dbms 输出不完整。

回答by Rene

Don't know about your code. Here is how it works for me: Whenever I create a function returning a clob value I do this:

不知道你的代码。这是它对我的工作方式:每当我创建一个返回 clob 值的函数时,我都会这样做:

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

When concatenating values into a clob I use a function:

将值连接到 clob 时,我使用了一个函数:

   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;

回答by Mahan

You have to use

你必须使用

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

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

e.g

例如

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

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

But you can print in a string max 4000 character, you can then use this in a looping function to print 4000 characters in each line.

但是您可以打印最多 4000 个字符的字符串,然后您可以在循环函数中使用它在每行中打印 4000 个字符。