'PLS-00103 Encountered the symbol "+" ...' 尝试在触发器中连接一些字符串时出错
'PLS-00103 Encountered the symbol "+" ...' error when trying to concatenate some strings in a trigger
我有一个 SQL table,其中一个特定的 record ID
(主键)可以有多个 Contact ID
。我想创建一个触发器,每次添加新行时,它都会检查 record ID
是否存在,如果存在,它会将新的 Contact ID
添加到当前的 Contact ID
字段用逗号分隔(本质上是创建一个列表)。因此,对于多个 Contact ID
,该字段可能变为:
Contact123, Contact456, Contact999
为此,我编写了以下触发器:
CREATE OR REPLACE
TRIGGER "TEST_INSERT" BEFORE
INSERT ON "TEST_INSERT" REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROW DECLARE REC_COUNT INTEGER;
BEGIN
SELECT COUNT(*)
INTO REC_COUNT
FROM TEST_INSERT
WHERE RECORDID = :NEW.RECORDID;
IF REC_COUNT > 0 THEN
CONTACTID + ', ' + :NEW.CONTACTID AS CONTACTID; --This is the line where I'm getting the error
END IF;
END;
我收到关于 +
符号以及 AS
操作的错误。我是不是完全用错了方法?
谢谢
在SQL Server 和Microsoft Access 中,您使用+ 连接,但在oracle 中,您使用||连接并在 mySQL 中使用 CONCAT 函数。您确定在您的情况下您使用的是正确的连接(如果我没记错的话 PLS 意味着它是一个 oracle 错误,所以您应该使用 || 而不是 +)?
您不能在触发器中将插入更改为更新。无论如何,您的错误行中有几个问题:
CONTACTID + ', ' + :NEW.CONTACTID AS CONTACTID;
以及使用 + 代替 ||对于串联,您没有将该新值分配给变量 - CONACTID
不存在于您正在使用的 PL/SQL 范围内,尽管您可能将串联作为更新的一部分(也没有 AS
子句),你不能在插入前插入 for-each-row 插入触发器中进行更新,因为你会遇到一个变异的 table 错误,即使它有效插入仍然会发生。
看来您确实想做一个 'upsert' - 如果现有记录存在则更新它,如果不存在则添加新记录。在 Oracle 中,您可以使用 the merge
statement 来做到这一点。这是一个示例,我将其包装在一个过程中只是为了使调用更清晰并减少重复——它通常只是简单的 SQL 而不是嵌入 PL/SQL:
create table test_merge (recordid number primary key,
contactid varchar2(4000));
create procedure p_merge(p_recordid number, p_contactid number) as
begin
merge into test_merge t
using (select p_recordid as recordid, p_contactid as contactid from dual) x
on (t.recordid = x.recordid)
when matched then
update set contactid = t.contactid ||','|| x.contactid
when not matched then
insert (recordid, contactid) values (x.recordid, x.contactid);
end;
/
exec p_merge (1, 123);
exec p_merge (1, 234);
exec p_merge (1, 456);
exec p_merge (2, 567);
select * from test_merge;
RECORDID CONTACTID
---------- --------------------
1 123,234,456
2 567
但是存储以逗号分隔的非规范化数据列表并不是一个好主意。您需要考虑如何修改该值(如果您必须删除联系人,例如,或希望对他们进行排序)以及您将如何使用字符串中的值 - 假设每个联系人 ID 都是对另一个联系人的引用table 您必须解构字符串才能进行连接。您也受到限制,但字符串列的最大大小。
最好有一个单独的 table 链接记录和联系人 ID:
create table test_parent (recordid number primary key);
create table test_child (recordid number references test_parent(recordid),
contactid number);
insert into test_parent (recordid) values (1);
insert into test_parent (recordid) values (2);
insert into test_child (recordid, contactid) values (1, 123);
insert into test_child (recordid, contactid) values (1, 234);
insert into test_child (recordid, contactid) values (1, 456);
insert into test_child (recordid, contactid) values (2, 567);
如果您想查看以逗号分隔的列表,请在需要时使用字符串聚合生成该列表。 11g 及更高版本需要 the built-in listagg
function 执行此操作:
select p.recordid,
listagg(c.contactid, ',') within group (order by c.contactid) as contactids
from test_parent p
left join test_child c on c.recordid = p.recordid
group by p.recordid
order by p.recordid;
RECORDID CONTACTIDS
---------- --------------------
1 123,234,456
2 567
我有一个 SQL table,其中一个特定的 record ID
(主键)可以有多个 Contact ID
。我想创建一个触发器,每次添加新行时,它都会检查 record ID
是否存在,如果存在,它会将新的 Contact ID
添加到当前的 Contact ID
字段用逗号分隔(本质上是创建一个列表)。因此,对于多个 Contact ID
,该字段可能变为:
Contact123, Contact456, Contact999
为此,我编写了以下触发器:
CREATE OR REPLACE
TRIGGER "TEST_INSERT" BEFORE
INSERT ON "TEST_INSERT" REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROW DECLARE REC_COUNT INTEGER;
BEGIN
SELECT COUNT(*)
INTO REC_COUNT
FROM TEST_INSERT
WHERE RECORDID = :NEW.RECORDID;
IF REC_COUNT > 0 THEN
CONTACTID + ', ' + :NEW.CONTACTID AS CONTACTID; --This is the line where I'm getting the error
END IF;
END;
我收到关于 +
符号以及 AS
操作的错误。我是不是完全用错了方法?
谢谢
在SQL Server 和Microsoft Access 中,您使用+ 连接,但在oracle 中,您使用||连接并在 mySQL 中使用 CONCAT 函数。您确定在您的情况下您使用的是正确的连接(如果我没记错的话 PLS 意味着它是一个 oracle 错误,所以您应该使用 || 而不是 +)?
您不能在触发器中将插入更改为更新。无论如何,您的错误行中有几个问题:
CONTACTID + ', ' + :NEW.CONTACTID AS CONTACTID;
以及使用 + 代替 ||对于串联,您没有将该新值分配给变量 - CONACTID
不存在于您正在使用的 PL/SQL 范围内,尽管您可能将串联作为更新的一部分(也没有 AS
子句),你不能在插入前插入 for-each-row 插入触发器中进行更新,因为你会遇到一个变异的 table 错误,即使它有效插入仍然会发生。
看来您确实想做一个 'upsert' - 如果现有记录存在则更新它,如果不存在则添加新记录。在 Oracle 中,您可以使用 the merge
statement 来做到这一点。这是一个示例,我将其包装在一个过程中只是为了使调用更清晰并减少重复——它通常只是简单的 SQL 而不是嵌入 PL/SQL:
create table test_merge (recordid number primary key,
contactid varchar2(4000));
create procedure p_merge(p_recordid number, p_contactid number) as
begin
merge into test_merge t
using (select p_recordid as recordid, p_contactid as contactid from dual) x
on (t.recordid = x.recordid)
when matched then
update set contactid = t.contactid ||','|| x.contactid
when not matched then
insert (recordid, contactid) values (x.recordid, x.contactid);
end;
/
exec p_merge (1, 123);
exec p_merge (1, 234);
exec p_merge (1, 456);
exec p_merge (2, 567);
select * from test_merge;
RECORDID CONTACTID
---------- --------------------
1 123,234,456
2 567
但是存储以逗号分隔的非规范化数据列表并不是一个好主意。您需要考虑如何修改该值(如果您必须删除联系人,例如,或希望对他们进行排序)以及您将如何使用字符串中的值 - 假设每个联系人 ID 都是对另一个联系人的引用table 您必须解构字符串才能进行连接。您也受到限制,但字符串列的最大大小。
最好有一个单独的 table 链接记录和联系人 ID:
create table test_parent (recordid number primary key);
create table test_child (recordid number references test_parent(recordid),
contactid number);
insert into test_parent (recordid) values (1);
insert into test_parent (recordid) values (2);
insert into test_child (recordid, contactid) values (1, 123);
insert into test_child (recordid, contactid) values (1, 234);
insert into test_child (recordid, contactid) values (1, 456);
insert into test_child (recordid, contactid) values (2, 567);
如果您想查看以逗号分隔的列表,请在需要时使用字符串聚合生成该列表。 11g 及更高版本需要 the built-in listagg
function 执行此操作:
select p.recordid,
listagg(c.contactid, ',') within group (order by c.contactid) as contactids
from test_parent p
left join test_child c on c.recordid = p.recordid
group by p.recordid
order by p.recordid;
RECORDID CONTACTIDS
---------- --------------------
1 123,234,456
2 567