我有一个Oracle程序,我希望以某种方式通用。我想:
varchar
参数EXECUTE IMMEDIATE
动态选择数据%ROWTYPE
变量第三点似乎是一个问题。我不确定我是否可以在过程体内动态创建一个类型。有这样的事情会很棒:
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;
答案 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对象类型以执行立即执行。