表名中的%ROWTYPE变量

时间:2014-10-24 14:20:08

标签: oracle procedure rowtype

我有一个Oracle程序,我希望以某种方式通用。我想:

  1. 将表名称作为varchar参数
  2. 传递
  3. 使用EXECUTE IMMEDIATE动态选择数据
  4. 将结果存储在传递类型的%ROWTYPE变量
  5. 第三点似乎是一个问题。我不确定我是否可以在过程体内动态创建一个类型。有这样的事情会很棒:

    procedure CHANGE_GENERIC(tableName in VARCHAR2, someOldVal in integer,
                              someNewVal in integer) is
    v_sql varchar2(200);
    
    begin   
    
       v_sql := 'select * from ' || tableName || 'where ID = ' || someOldVal;
       EXECUTE IMMEDIATE v_sql1 into **myDynamicRowThatIDontHave**;
    
       -- some other code
    end;
    

3 个答案:

答案 0 :(得分:3)

您可能无法做到这一点(至少没有用)。

您可以构建一个完整的匿名PL / SQL块

v_plsql := 'DECLARE ' ||
           '  l_row ' || p_table_name || '%rowtype; ' ||
           'BEGIN ' ||
           '  SELECT * ' ||
           '    INTO l_row ' ||
           '    FROM ' || p_table_name ||
           '    WHERE id = ' || p_some_old_value || ';' ||
           ...
EXECUTE IMMEDIATE v_plsql;

一般而言,在您开始在运行时使用动态PL / SQL之前很久,您真的想退后一步,评估是否有更简单的解决方案来解决您遇到的任何问题。例如,有许多框架可以为每个表动态生成CRUD包。这是使用动态PL / SQL,但它只是作为构建的一部分而不是每次想要更新数据时都这样做。

答案 1 :(得分:1)

看看DBMS_SQL 这是一个例子:

DECLARE
    YourTable VARCHAR2(30) := 'MY_TABLE';
    cur SYS_FERCURSOR;
    curid NUMBER;
    desctab DBMS_SQL.DESC_TAB;
    colcnt NUMBER; -- total number of columns
    res NUMBER;

    namevar VARCHAR2(4000);
    numvar NUMBER;
    datevar DATE;
    ... more if needed
BEGIN

    OPEN cur FOR 'SELECT * FROM '||YourTable;               
    curid := DBMS_SQL.TO_CURSOR_NUMBER (cur);

    DBMS_SQL.DESCRIBE_COLUMNS(curid, colcnt, desctab);
    FOR i IN 1..colcnt LOOP -- loop over all columns
        IF desctab(i).col_type = 1 THEN
            DBMS_SQL.DEFINE_COLUMN(curid, i, namevar);
        ELSIF desctab(i).col_type = 2 THEN
            DBMS_SQL.DEFINE_COLUMN(curid, i, numvar);
        ELSIF desctab(i).col_type = 12 THEN
            DBMS_SQL.DEFINE_COLUMN(curid, i, datevar);
            .......
        ELSE
            DBMS_SQL.DEFINE_COLUMN(curid, i, namevar, 25);
        END IF;         
    END LOOP;
    -- Fetch Rows
    WHILE DBMS_SQL.FETCH_ROWS(curid) > 0 LOOP
        FOR i IN 1 .. colcnt LOOP
           IF (desctab(i).col_type = 1) THEN
              DBMS_SQL.COLUMN_VALUE(curid, i, namevar);
           ELSIF (desctab(i).col_type = 2) THEN
              DBMS_SQL.COLUMN_VALUE(curid, i, numvar);
           ELSIF (desctab(i).col_type = 12) THEN
              DBMS_SQL.COLUMN_VALUE(curid, i, datevar);
              ....
          END IF;
          --> do here something else with namevar or numvar or datevar or ...
       END LOOP;
    END LOOP;    
    DBMS_SQL.CLOSE_CURSOR(curid);

END;

但正如其他已经提到的回复一样,请仔细检查您是否真的需要这个"完整"动态。您没有告诉我们您对retunrned变量值的喜好。也许你不明确地需要它们。您还可以动态创建复杂语句并运行它们。

这里看到一个简单的例子(好吧,不是那么简单)我前段时间做过的。它使用不同对象类型的嵌套表更新多个表,而不使用任何变量。

CREATE OR REPLACE PROCEDURE UpdateNestedTables IS

    sqlstr VARCHAR2(1000);

    CURSOR NestedTables IS
    SELECT POCL_TABLE_NAME, FTC_NT_TABLE_NAME, PAR_COLUMN_NAME,
        FTC_MO_STRUCT_CONSTRUCTOR AS NT_COLUMN_NAME,
        FTC_MO_STRUCT_TYPE AS NT_OBJ_TYPE
    FROM T_PAR_OBJ_CLASSES
        JOIN T_PARAMETERS ON PAR_POCL_ID = POCL_ID
        JOIN T_FDN_TABLE_COLUMNS ON FTC_PAR_ID = PAR_ID;

BEGIN

    FOR aTab IN NestedTables LOOP
        sqlstr := 'UPDATE '
            || '(SELECT /*+ USE_HASH(a b) */ '||aTab.PAR_COLUMN_NAME||', FULL_DISTINCT_NAME '
            ||'  FROM '||SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA')||'.'||aTab.POCL_TABLE_NAME||' a '
            ||'  WHERE '||aTab.PAR_COLUMN_NAME||' IS NULL '
            ||'   AND FULL_DISTINCT_NAME =ANY '
            ||'    (SELECT FULL_DISTINCT_NAME FROM '||SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA')||'.'||aTab.FTC_NT_TABLE_NAME||' b)) wt '
            || 'SET ('||aTab.PAR_COLUMN_NAME||') = '
            || ' (WITH t AS ('
            || '    SELECT m.FULL_DISTINCT_NAME,'
            || '      CAST(MULTISET('
            || '        SELECT '||aTab.NT_COLUMN_NAME
            || '        FROM '||SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA')||'.'||aTab.FTC_NT_TABLE_NAME||' nt '
            || '        WHERE nt.FULL_DISTINCT_NAME = m.FULL_DISTINCT_NAME)'
            || '      AS '||aTab.NT_OBJ_TYPE||') AS MO_REF'
            || '    FROM '||SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA')||'.'||aTab.POCL_TABLE_NAME||' m'
            || '    GROUP BY FULL_DISTINCT_NAME)'
            || '  SELECT MO_REF '
            || '  FROM t '
            || '  WHERE t.FULL_DISTINCT_NAME = wt.FULL_DISTINCT_NAME)';
        EXECUTE IMMEDIATE sqlstr;
    END LOOP;

END UpdateNestedTables;
/

答案 2 :(得分:0)

我可以建议根据这些类型使用对象类型和对象表/视图。使用可以定义根类型并从中继承所有子类型。使用可以将根类型的变量传入/传出通用过程,并使用动态SQL内部处理将其转换为特定类型。您可以在/ out中传递SQL对象类型以执行立即执行。