PLSQL动态获取记录中属性的值?
首先,我对Oracle PLSQL非常生疏,我看到一些人说这是不可能做到的,其他人说这是可以做到的,我只是无法做到。任何帮助都将不胜感激 我正在尝试动态读取记录类型中列的值 我有一条带有令牌的消息,我需要用记录集中的值替换令牌 因此,该消息看起来像:[status]by[agent\u name] 我在另一个地方解析令牌 在java脚本中,我知道这可以通过:(将在控制台中运行) 我尝试使用替换变量,如果我使用: DBMS_OUTPUT.PUT_LINE(&agent_name)并在提示时输入v_记录(i).agent_name。我如何在飞行中实现这一点 答复:PLSQL动态获取记录中属性的值?,sql,oracle,dynamic,plsql,plsqldeveloper,Sql,Oracle,Dynamic,Plsql,Plsqldeveloper,首先,我对Oracle PLSQL非常生疏,我看到一些人说这是不可能做到的,其他人说这是可以做到的,我只是无法做到。任何帮助都将不胜感激 我正在尝试动态读取记录类型中列的值 我有一条带有令牌的消息,我需要用记录集中的值替换令牌 因此,该消息看起来像:[status]by[agent\u name] 我在另一个地方解析令牌 在java脚本中,我知道这可以通过:(将在控制台中运行) 我尝试使用替换变量,如果我使用: DBMS_OUTPUT.PUT_LINE(&agent_name)并在提示时输入v_
set serveroutput on;
DECLARE
type sr_record_map
IS
TABLE OF VARCHAR2(30) INDEX BY VARCHAR2(30);
type record_set
is
TABLE of sr_record_map index by BINARY_INTEGER;
v_current_rec sr_record_map;
v_record_set record_set;
v_token varchar2(30) := 'status';
v_token2 varchar2(30) := 'agent_name';
v_index number :=1;
begin
v_current_rec('status') := 'Open';
v_current_rec('agent_name') := 'John';
v_record_set(1) := v_current_rec;
v_current_rec('status') := 'Close';
v_current_rec('agent_name') := 'Joe';
v_record_set(2) := v_current_rec;
FOR i in 1..v_record_set.COUNT LOOP
v_current_rec := v_record_set(i);
DBMS_OUTPUT.PUT_LINE(v_current_rec(v_token) || ' by ' || v_current_rec(v_token2));
END LOOP;
end;
我认为用唱片类型是做不到的。对象类型可能是可行的,因为您可以从数据字典中查询字段,但这些字段通常不存在(尽管有一个名为11g的工具,如果启用该工具,它可能会允许) 由于您在使用记录类型的同一位置定义记录类型,并且如果您有可管理的字段数,则只需尝试替换每个令牌可能会更简单,如果消息中不存在令牌,这只会(!)浪费一点CPU:
declare
TYPE my_record is RECORD
(
status VARCHAR2(30),
agent_name varchar2(30)
);
TYPE my_record_array IS VARRAY(6) OF my_record;
v_records my_record_array := my_record_array();
v_current_rec my_record;
v_current_rec2 my_record;
v_message varchar2(50):= '[status] by [agent_name]';
v_result varchar2(50);
begin
v_current_rec.status := 'Open';
v_current_rec.agent_name := 'John';
v_records.extend;
v_records(1) := v_current_rec;
v_current_rec2.status := 'Close';
v_current_rec2.agent_name := 'Ron';
v_records.extend;
v_records(2) := v_current_rec2;
FOR i IN 1..v_records.COUNT LOOP
v_result := v_message;
v_result := replace(v_result, '[agent_name]', v_records(i).agent_name);
v_result := replace(v_result, '[status]', v_records(i).status);
DBMS_OUTPUT.PUT_LINE(v_result);
END LOOP;
END;
/
anonymous block completed
Open by John
Close by Ron
当然,它需要维护;如果将字段添加到记录类型中,则需要将匹配的replace
添加到正文中
我假设在现实世界中,消息文本(包含令牌)将被传递给一个过程。不过,我不确定是否值得解析这些标记,除非您需要它们来做其他事情。使用类似于Java中的映射的
DECLARE
type my_record_map
IS
TABLE OF VARCHAR2(30) INDEX BY VARCHAR2(30);
type my_record
IS
record
(
my_members my_record_map );
type final_map
IS
TABLE OF my_record INDEX BY VARCHAR2(20);
v_final_map final_map;
v_my_record_map my_record_map;
v_my_record my_record;
index_name VARCHAR2(100);
index_name_record VARCHAR2(100);
BEGIN
/* Individual Records as key value pairs with their Corresponding Columns */
/* You can put any member name inside */
v_my_record_map('status') := 'Open';
v_my_record_map('agent_name') := 'John';
v_my_record_map('added_by') := 'Maheshwaran';
/* Put it as a record */
v_my_record.my_members := v_my_record_map;
/* Put the record inside Another Map with any Key */
v_final_map('Record1') := v_my_record;
v_my_record_map('status') := 'Close';
v_my_record_map('agent_name') := 'Joe';
v_my_record_map('added_by') := 'Ravisankar';
v_my_record.my_members := v_my_record_map;
v_final_map('Record2') := v_my_record;
/* Take the First Key in the Outer most Map */
index_name := v_final_map.FIRST;
LOOP
/* status Here can be dynamic */
DBMS_OUTPUT.PUT_LINE(CHR(10)||'######'||v_final_map(index_name).my_members('status') ||' by '||v_final_map(index_name).my_members('agent_name')||'######'||CHR(10));
index_name_record := v_final_map(index_name).my_members.FIRST;
DBMS_OUTPUT.PUT_LINE('$ Ávailable Other Members + Values.. $'||CHR(10));
LOOP
DBMS_OUTPUT.PUT_LINE(' '||index_name_record ||'='||v_final_map(index_name).my_members(index_name_record));
index_name_record := v_final_map(index_name).my_members.NEXT(index_name_record);
EXIT WHEN index_name_record IS NULL;
END LOOP;
/* Next gives you the next key */
index_name := v_final_map.NEXT(index_name);
EXIT WHEN index_name IS NULL;
END LOOP;
END;
/
输出:
######Open by John######
$ Ávailable Other Members + Values.. $
added_by=Maheshwaran
agent_name=John
status=Open
######Close by Joe######
$ Ávailable Other Members + Values.. $
added_by=Ravisankar
agent_name=Joe
status=Close
作为一个例子,我附加了一些简单的代码,通过这些代码,您可以根据表名和id值动态比较任何表的任何两个记录,以获得数据的差异
DECLARE
p_id_1 NUMBER DEFAULT 697403;
p_id_2 NUMBER DEFAULT 697402;
p_table_name VARCHAR2(200) DEFAULT 'Name of the table';
V_result_1 VARCHAR2(2000);
V_result_2 VARCHAR2(2000);
CURSOR cur IS
SELECT * FROM ALL_TAB_COLUMNS WHERE table_name = p_table_name ;
BEGIN
FOR rec IN cur LOOP
EXECUTE IMMEDIATE
'SELECT ' || rec.COLUMN_NAME || ' FROM ' || P_TABLE_NAME ||
' WHERE ID = :1 '
INTO V_result_1
USING P_ID_1
;
EXECUTE IMMEDIATE
'SELECT ' || rec.COLUMN_NAME || ' FROM ' || P_TABLE_NAME ||
' WHERE ID = :1 '
INTO V_result_2
USING P_ID_2
;
IF NVL(v_result_1, 0) <> NVL(v_result_2,0) THEN
DBMS_OUTPUT.PUT_LINE('Column_name ' || rec.column_name || ' ' || v_result_1 || '\' || v_result_2);
END IF;
END LOOP;
END;
声明
p_id_1编号默认为697403;
p_id_2编号默认为697402;
p_table_name VARCHAR2(200)默认“表名”;
V_result_1 VARCHAR2(2000年);
V_result_2 VARCHAR2(2000);
光标cur是
从所有_选项卡_列中选择*,其中table_name=p_table_name;
开始
对于cur循环中的rec
立即执行
从“|| P|u TABLE_NAME”中选择“| | rec.COLUMN_NAME | |”||
'其中ID=:1'
进入V_结果_1
使用P_ID_1
;
立即执行
从“|| P|u TABLE_NAME”中选择“| | rec.COLUMN_NAME | |”||
'其中ID=:1'
进入V_结果_2
使用P_ID_2
;
如果NVL(v_结果_1,0)NVL(v_结果_2,0),则
DBMS|u OUTPUT.PUT|u LINE('Column|u name'| rec.Column|u name | |'''| v| u result_1 | |'\'| v|u result_2);
如果结束;
端环;
结束;
您说,您的记录可能有任何成员(列),您想通过选择一个来打印它们?我有多条消息,可能有任意数量的令牌。我知道这些字段存在于记录中。因此,如果我有一个令牌agent_name,我想计算字符串v_records(I).agent_name并从记录中获取值。因此,我可以用值替换消息中的令牌。我们提出了类似的方法,但基本上是尝试使其成为动态的,以便我们可以将数据添加到发送到过程中的记录中,然后将新令牌插入消息中。此进程将获得一个记录集和一条消息。创建一个“自动”映射到记录中的列。@John-只要记录中的每个字段都有一个replace
,我不清楚将其动态化能实现什么效果。除非在记录中定义了字段,否则无法向消息中添加新令牌?也许您根本不需要记录集合,但如果字段需要在运行时更改,则需要关联数组?这只是一个原型。该类型实际上是在其他地方定义的。我正在努力减少变化点。我们有几个进程将向这个进程发送记录集。我想避免每次其他进程更改时都必须更改此值。@John-您只需在类型更改时更改此值,而不必更改调用者。其中定义了类型;您的实际类型实际上是记录类型(比如在包中定义的),还是在模式级别定义的对象类型?我认为你不能用唱片类型来做。您可以从PL/Scope中获取字段名并对其进行循环,但我认为没有一种方法可以动态引用它们。(即使使用动态SQL攻击,也不能将记录作为绑定变量传递-PLS-00457)。就是这样。我将在我的问题中给出这个例子的答案。
######Open by John######
$ Ávailable Other Members + Values.. $
added_by=Maheshwaran
agent_name=John
status=Open
######Close by Joe######
$ Ávailable Other Members + Values.. $
added_by=Ravisankar
agent_name=Joe
status=Close
DECLARE
p_id_1 NUMBER DEFAULT 697403;
p_id_2 NUMBER DEFAULT 697402;
p_table_name VARCHAR2(200) DEFAULT 'Name of the table';
V_result_1 VARCHAR2(2000);
V_result_2 VARCHAR2(2000);
CURSOR cur IS
SELECT * FROM ALL_TAB_COLUMNS WHERE table_name = p_table_name ;
BEGIN
FOR rec IN cur LOOP
EXECUTE IMMEDIATE
'SELECT ' || rec.COLUMN_NAME || ' FROM ' || P_TABLE_NAME ||
' WHERE ID = :1 '
INTO V_result_1
USING P_ID_1
;
EXECUTE IMMEDIATE
'SELECT ' || rec.COLUMN_NAME || ' FROM ' || P_TABLE_NAME ||
' WHERE ID = :1 '
INTO V_result_2
USING P_ID_2
;
IF NVL(v_result_1, 0) <> NVL(v_result_2,0) THEN
DBMS_OUTPUT.PUT_LINE('Column_name ' || rec.column_name || ' ' || v_result_1 || '\' || v_result_2);
END IF;
END LOOP;
END;