在PL-SQL中动态替换单引号和双引号

时间:2019-03-27 13:04:06

标签: oracle plsql

我有以下查询:

select ''|| CHR(10) || CHR(10)  
         || 'INSERT into ' || v_TableName || '(' || v_Columns || ')' || CHR(10) 
         || 'VALUES (' || SUBSTR(v_Values,1, LENGTH(RTRIM(v_Values))-1) || ')' from dual;

执行时我得到:

v_TableName ='tblRecHistCalc',

v_Columns ='average_eps,company_id,rec_code,rec_date'

v_Values ='3.3887524216711,25597,'B','20-Mar-2019','

因此查询变为:

select ''|| CHR(10) || CHR(10)  
         || 'INSERT into ' || 'tblRecHistCalc' || '(' || 'average_eps,company_id,rec_code,rec_date' || ')' || CHR(10) 
         || 'VALUES (' || SUBSTR('3.3887524216711,25597,'B','20-Mar-2019',',1, LENGTH(RTRIM('3.3887524216711,25597,'B','20-Mar-2019','))-1) || ')' from dual;

但是我无法执行上述查询,因为'B'和'20 -Mar-2019'中有单引号,这使查询无法成功执行。

我尝试将其更改为以下内容:

select ''|| CHR(10) || CHR(10)  
         || 'INSERT into ' || 'tblRecHistCalc' || '(' ||'average_eps,company_id,rec_code,rec_date' || ')' || CHR(10) 
         || 'VALUES (' || SUBSTR(Replace('3.3887524216711,25597,'B','20-Mar-2019',',''','''''),1, LENGTH(RTRIM('3.3887524216711,25597,'B','20-Mar-2019','))-1) || ')' from dual;

但是查询仍然无法成功执行。

我该如何实现?

编辑:

根据 Alex Poole 的要求, 变量声明如下:

v_TableName NVARCHAR2(50);

v_Columns Nvarchar2(4000);

v_Values Nvarchar2(4000);

v_Count NUMBER(10);

v_SQL Nvarchar2(4000):='';

下面显示了如何填充三个变量:

WHILE (v_Count > 0) 
LOOP 
v_Columns := ''; 
v_Values := ''; 

-- Gets 1 table name at a time 
SELECT TableName INTO v_TableName  
FROM ( 
        SELECT ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY TableName) as Rowcnt, TableName  
        FROM 
        --#tmp_Templates_Load_InsertSQL STARTS
        (

            SELECT D.TableName, D.ColumnName, D.Val
            FROM 

            --#tmp_Templates_Load_Destinations STARTS
            (         
                SELECT ID, TableName, ColumnName, Val  
                FROM tblTemplates_Load_OtherObjects_Raw OO  
                JOIN tblTemplates_Fields F ON OO.OtherObjectsField = F.FieldName 
                WHERE TemplateType IN ('All','ALL', v_TemplateType) 
                AND OO.Val IS NOT NULL 
                AND  (TemplateVersion = p_TemplateVersion or (TemplateVersion is null and p_TemplateVersion <> 'V8')) 

                UNION 

                SELECT FieldID, TableName, ColumnName, Val 
                FROM tblTemplates_Fields_OtherDestinations OD 
                JOIN  
                ( 
                    SELECT ID, Val 
                    FROM tblTemplates_Load_OtherObjects_Raw OO  
                    JOIN tblTemplates_Fields F ON OO.OtherObjectsField = F.FieldName 
                    WHERE TemplateType IN ('All','ALL', v_TemplateType) 
                    AND OO.Val IS NOT NULL 
                    AND    (TemplateVersion = p_TemplateVersion or (TemplateVersion is null and p_TemplateVersion <> 'V8')) 

                ) UsedIDs 
                ON OD.FieldID = UsedIDs.ID


            ) D
            --#tmp_Templates_Load_Destinations ENDS

            JOIN USER_TAB_COLS C  ON upper(D.TableName) = upper(C.TABLE_NAME) AND upper(D.ColumnName) = upper(C.COLUMN_NAME)
            WHERE (v_UpdateComp = 0 OR D.TableName <> 'tblComp') 
            AND (v_UpdateCompInd = 0 OR D.TableName <> 'tblCompInd') 
            ORDER BY D.TableName, D.ColumnName
        )

        --#tmp_Templates_Load_InsertSQL ENDS
         GROUP BY TableName 
    ) DistinctTableNames 
WHERE Rowcnt = v_Count; 



-- Get lists of all columns  for current table 
 Select  LISTAGG( ColumnName, ',' ) WITHIN GROUP ( ORDER BY ROWNUM ) 
          into v_Columns
 FROM 
 --#tmp_Templates_Load_InsertSQL STARTS
  (

        SELECT D.TableName, D.ColumnName, D.Val
        FROM 

        --#tmp_Templates_Load_Destinations STARTS
        (         
            SELECT ID, TableName, ColumnName, Val  
            FROM tblTemplates_Load_OtherObjects_Raw OO  
            JOIN tblTemplates_Fields F ON OO.OtherObjectsField = F.FieldName 
            WHERE TemplateType IN ('All','ALL', v_TemplateType) 
            AND OO.Val IS NOT NULL 
            AND  (TemplateVersion = p_TemplateVersion or (TemplateVersion is null and p_TemplateVersion <> 'V8')) 

            UNION 

            SELECT FieldID, TableName, ColumnName, Val 
            FROM tblTemplates_Fields_OtherDestinations OD 
            JOIN  
            ( 
                SELECT ID, Val 
                FROM tblTemplates_Load_OtherObjects_Raw OO  
                JOIN tblTemplates_Fields F ON OO.OtherObjectsField = F.FieldName 
                WHERE TemplateType IN ('All','ALL', v_TemplateType) 
                AND OO.Val IS NOT NULL 
                AND    (TemplateVersion = p_TemplateVersion or (TemplateVersion is null and p_TemplateVersion <> 'V8')) 

            ) UsedIDs 
            ON OD.FieldID = UsedIDs.ID


        ) D
        --#tmp_Templates_Load_Destinations ENDS

        JOIN USER_TAB_COLS C  ON upper(D.TableName) = upper(C.TABLE_NAME) AND upper(D.ColumnName) = upper(C.COLUMN_NAME)
        WHERE (v_UpdateComp = 0 OR D.TableName <> 'tblComp') 
        AND (v_UpdateCompInd = 0 OR D.TableName <> 'tblCompInd') 
        ORDER BY D.TableName, D.ColumnName
   )

   --#tmp_Templates_Load_InsertSQL ENDS

WHERE TableName = v_TableName ;

-- Get lists of all  values for current table 

Select   LISTAGG(
            CASE ISNUMERIC(Val) 
                WHEN 1 THEN Val 
                WHEN 0 THEN '''' || REPLACE(LTRIM(RTRIM(Val)), '''','''''') || '''' 
            END
            || ',' ) WITHIN GROUP ( ORDER BY ROWNUM ) 
            into v_Values
 FROM 
 --#tmp_Templates_Load_InsertSQL STARTS
  (

        SELECT D.TableName, D.ColumnName, D.Val
        FROM 

        --#tmp_Templates_Load_Destinations STARTS
        (         
            SELECT ID, TableName, ColumnName, Val  
            FROM tblTemplates_Load_OtherObjects_Raw OO  
            JOIN tblTemplates_Fields F ON OO.OtherObjectsField = F.FieldName 
            WHERE TemplateType IN ('All','ALL', v_TemplateType) 
            AND OO.Val IS NOT NULL 
            AND  (TemplateVersion = p_TemplateVersion or (TemplateVersion is null and p_TemplateVersion <> 'V8')) 

            UNION 

            SELECT FieldID, TableName, ColumnName, Val 
            FROM tblTemplates_Fields_OtherDestinations OD 
            JOIN  
            ( 
                SELECT ID, Val 
                FROM tblTemplates_Load_OtherObjects_Raw OO  
                JOIN tblTemplates_Fields F ON OO.OtherObjectsField = F.FieldName 
                WHERE TemplateType IN ('All','ALL', v_TemplateType) 
                AND OO.Val IS NOT NULL 
                AND    (TemplateVersion = p_TemplateVersion or (TemplateVersion is null and p_TemplateVersion <> 'V8')) 

            ) UsedIDs 
            ON OD.FieldID = UsedIDs.ID


        ) D
        --#tmp_Templates_Load_Destinations ENDS

        JOIN USER_TAB_COLS C  ON upper(D.TableName) = upper(C.TABLE_NAME) AND upper(D.ColumnName) = upper(C.COLUMN_NAME)
        WHERE (v_UpdateComp = 0 OR D.TableName <> 'tblComp') 
        AND (v_UpdateCompInd = 0 OR D.TableName <> 'tblCompInd') 
        ORDER BY D.TableName, D.ColumnName
   )

   --#tmp_Templates_Load_InsertSQL ENDS

WHERE TableName = v_TableName ;



-- Build Insert and append to v_SQL variable 
v_SQL:= v_SQL || CHR(10) || CHR(10)  
        || 'INSERT into ' || v_TableName || '(' || SUBSTR(v_Columns, 1, LENGTH(RTRIM(v_Columns))) || ')' || CHR(10) 
        || 'VALUES (' || SUBSTR(v_Values, 1, LENGTH(RTRIM(v_Values))-1) || ')' ;

v_Count := v_Count -1; 
   EXECUTE IMMEDIATE  v_SQL;
end loop;

1 个答案:

答案 0 :(得分:3)

您尚未显示您当前如何将一个语句转换为另一个语句-我怀疑您使用不需要的动态SQL-但您可以这样做:

declare
  v_TableName varchar2(30) := 'tblRecHistCalc';
  v_Columns varchar2(80) := 'average_eps,company_id,rec_code,rec_date';
  v_Values varchar2(80) := q'[3.3887524216711,25597,'B','20-Mar-2019',]';

  v_sql varchar2(4000);
begin
  select ''|| CHR(10) || CHR(10)  
           || 'INSERT into ' || v_TableName || '(' || v_Columns || ')' || CHR(10) 
           || 'VALUES (' || SUBSTR(v_Values,1, LENGTH(RTRIM(v_Values))-1) || ')'
  into v_sql
  from dual;

  dbms_output.put_line(v_query);

end;
/

或使用赋值而不是对偶表进行选择:

  v_sql := CHR(10) || CHR(10)  
           || 'INSERT into ' || v_TableName || '(' || v_Columns || ')' || CHR(10) 
           || 'VALUES (' || SUBSTR(v_Values,1, LENGTH(RTRIM(v_Values))-1) || ')';

这两个都会生成:

INSERT into tblRecHistCalc(average_eps,company_id,rec_code,rec_date)
VALUES (3.3887524216711,25597,'B','20-Mar-2019')


PL/SQL procedure successfully completed.

'20-Mar-2019'仍然只是一个字符串,因此您依赖于隐式转换和NLS设置-如果立即执行该插入操作,则它们至少会匹配,但是会浪费时间的时间部分任何值(使用此模型;可能会产生更糟的影响),最好使用与字符串值之间的显式转换。

我也不清楚您的代码-不是我检查的太详细了-v_Values的结尾是逗号吗?但是您也可以trim()关闭它,而不用使用substr()