我是PL SQL的新手并且还在学习,但我需要解决一个问题,而且我对PL SQL的了解不够快,无法快速解决我的问题。
我引用了两个表:用户和属性。我有一个过程需要3个参数: attrib_id , uid , attrib_value 。
我首先使用 attrib_id 查询属性表,以返回属性名称并将其分配给变量。我的代码到目前为止。
接下来,我想在另一个select语句中使用从前一个select语句创建的变量来查询users表,并返回与该变量所代表的属性关联的当前值。
CODE:
PROCEDURE value_update_proc_z(attrib_id INTEGER, uid IN VARCHAR2, attrib_value IN VARCHAR2)
IS
v_old_attrib_name attributes.attribute_name%TYPE;
v_oldattrib_value varchar2(100);
v_mymsg varchar2(2000);
BEGIN
EXECUTE IMMEDIATE 'SELECT attrib_name FROM attributes WHERE indx = ''' || attrib_id || '''' INTO v_old_attrib_name;
EXECUTE IMMEDIATE 'SELECT' || v_old_attrib_name || 'FROM USERS WHERE USERID = ''' || uid || '''' INTO v_oldattrib_value;
v_mymsg := v_old_attrib_name || ' ' || v_oldattrib_value;
END value_update_proc_z;
第一个查询应该根据传递给过程的数字从属性表中返回一个值。例如,如果 attrib_id = 1,则查询将返回first_name,如果 attrib_id = 2,则返回last_name,如果 attrib_id = 3,将被退回的电子邮件。返回的值将分配给变量 v_old_attrib_name 。
在我的select语句中使用变量 v_old_attrib_name ,我希望第二个查询会返回一个值,例如; last_name将返回williams,否则电子邮件将返回bob@somewhere.com。此查询的结果将分配给变量 v_oldattrib_value 。
目前,第一个Execute Immediate工作,当我显示消息时,我可以看到该变量的值,但是当我添加第二个Execute Immediate时,我收到一条消息,说明操作无法完成。这不是系统生成的错误,它是由前一位开发人员设置的消息。
我愿意接受改进建议。
谢谢!
答案 0 :(得分:5)
动态SQL很难,因为它将编译错误转变为运行时错误。令人惊讶的是,使用动态SQL在这里发布的问题是一个简单的拼写错误,如果该语句是作为静态SQL编写的话很容易发现。这似乎就是这种情况。
这里的标准建议是首先以静态形式编写SQL,因此您知道代码可以正常工作。然后将其转换为模板SQL以进行动态执行,注意空格,名称等。您的第二个语句是在连接的v_old_attrib_name
变量的任一侧模板SQL中缺少空格。
另外,如果静态SQL有效,请不要使用动态SQL。例如,你的第一个陈述可以 - 而且应该是 - 静态。
PROCEDURE value_update_proc_z(
attrib_id INTEGER,
uid IN VARCHAR2,
attrib_value IN VARCHAR2)
IS
v_old_attrib_name attributes.attribute_name%TYPE;
v_oldattrib_value varchar2(100);
v_mymsg varchar2(2000);
BEGIN
SELECT attrib_name
INTO v_old_attrib_name
FROM attributes
WHERE indx = attrib_id ;
EXECUTE IMMEDIATE
'SELECT ' || v_old_attrib_name || ' FROM USERS WHERE USERID = :1'
INTO v_oldattrib_value
using uid;
v_mymsg := v_old_attrib_name || ' ' || v_oldattrib_value;
dbms_output.put_line(v_mymsg);
END value_update_proc_z;
在你的问题中注意到这一行。
“这不是系统生成的错误,而是由前任开发人员设置的消息。”
但是看起来这个以前的开发者是坏代码王子。他们不仅用可怕的EAV implementation给你带来了麻烦,而且他们也在压制错误信息。诸如操作无法完成的通用消息对任何人都不利,尤其是我们。您需要知道实际的PL / SQL错误消息,以便了解程序失败的原因,这是解决问题的关键。
现在,设计良好的系统将具有某种形式的日志记录,可以显示和/或存储真正的SQLERRM。您似乎并没有在设计良好的系统上工作,但是您是否有任何错误记录?
答案 1 :(得分:2)
在第二个陈述中
EXECUTE IMMEDIATE 'SELECT' || v_old_attrib_name || 'FROM USERS WHERE USERID
...
在变量space
之前和之后应至少存在一个v_old_attrib_name
,如下所示:
EXECUTE IMMEDIATE 'SELECT ' || v_old_attrib_name || ' FROM USERS WHERE USERID
...
答案 2 :(得分:0)
请在下面找到工作示例。让我知道你不明白...
问题1:我是在获取attrib_value但是使用v_old_attrib_name attributes.attribute_name%TYPE;
[Attribute_Name]声明了变量。应该是v_old_attrib_name attributes.attrib_name%TYPE;
问题2:如上面另一个答案中所述,您在查询中缺少一些空格。
问题3:您没有 out_variable ,IDK您查看返回值的计划是什么。
create table attributes (attrib_name varchar2(20), indx number(2));
insert into attributes values('LAST_NAME',1)
create table USERS (userid number(2), last_Name varchar2(100))
insert into users values (12,'Williams')
<强>步骤:强>
create or replace PROCEDURE value_update_proc_z(attrib_id INTEGER, uid IN VARCHAR2, attrib_value OUT VARCHAR2)
IS
v_old_attrib_name attributes.attrib_name%TYPE;
v_oldattrib_value varchar2(100);
BEGIN
EXECUTE IMMEDIATE 'SELECT attrib_name FROM attributes WHERE indx = ''' || attrib_id || '''' INTO v_old_attrib_name;
EXECUTE IMMEDIATE 'SELECT ' || v_old_attrib_name || ' FROM USERS WHERE USERID = ''' || uid || '''' INTO v_oldattrib_value;
attrib_value := v_old_attrib_name || ' ' || v_oldattrib_value;
END value_update_proc_z;
执行:请注意,我们正在打印出一个输出变量
DECLARE
ATTRIB_ID NUMBER;
"UID" VARCHAR2(32767);
ATTRIB_VALUE VARCHAR2(32767);
BEGIN
ATTRIB_ID := 1;
"UID" := 12;
ATTRIB_VALUE := NULL;
VALUE_UPDATE_PROC_Z ( ATTRIB_ID, "UID", ATTRIB_VALUE );
DBMS_OUTPUT.Put_Line('ATTRIB_VALUE = ' || ATTRIB_VALUE);
DBMS_OUTPUT.Put_Line('');
COMMIT;
END;
答案 3 :(得分:0)
我根据您的架构中的要求创建了Sample表。我发现您必须在代码中进行3项更改才能正常工作。
1。) v_old_attrib_name attributes.attribute_name%TYPE 已更改为 v_old_attrib_name attributes.attrib_name%TYPE(根据开始块中的代码)。
我说的是上面的更改,因为在开始块中,当您在属性表上编写选择查询时,select子句中的列是“attrib_name”而不是“attribute_name”。
2.。)当您使用动态SQL时,您无法直接将列或table_name替换为变量,因为oracle在运行时需要它们来执行查询。为避免这种情况,您必须添加另一个变量,在该变量中您将形成动态查询,然后在执行立即中使用它。您将在下面的代码中看到。
3。)当您编写动态SQL时,请确保提供适当的空格,以便不会将任何内容相互连接。您也可以在下面的代码中看到。
以下代码:
PROCEDURE value_update_proc_z(attrib_id INTEGER, uid IN VARCHAR2, attrib_value IN VARCHAR2)
is
v_old_attrib_name attributes.attrib_name%TYPE;
v_oldattrib_value varchar2(100);
v_mymsg varchar2(2000);
v_sql varchar2(4000);
BEGIN
EXECUTE IMMEDIATE 'SELECT attrib_name FROM attributes WHERE indx = ''' || attrib_id || '''' INTO v_old_attrib_name;
v_sql:='SELECT ' || v_old_attrib_name || ' FROM USERS WHERE USERID = ''' || uid || '''' ;
EXECUTE IMMEDIATE v_sql INTO v_oldattrib_value;
v_mymsg := v_old_attrib_name || ' ' || v_oldattrib_value;
END value_update_proc_z;
希望这能解决您的问题。
由于 ANKIT。