插入返回 IDENTITY 生成 ORA 00933
Posted
技术标签:
【中文标题】插入返回 IDENTITY 生成 ORA 00933【英文标题】:INSERT returning IDENTITY generating ORA 00933 【发布时间】:2015-09-19 15:17:24 【问题描述】:我正在尝试将单个记录插入到表中并返回通过 ASP.net/Visual Studio 添加到记录中的序列号。但是,我收到了上面提到的错误。最初我认为我的错误是因为它认为我可能会返回多个记录,但即使在重写了几种方法之后,错误仍然存在。关于这个主题存在多个帖子,但它们似乎都围绕着插入多条记录的可能性。
我怀疑因为我正在使用“select... from dual”,它仍然认为我可以插入多个记录。我显然不需要“select...from dual”,只是我想使用 WHERE 子句来保证目标表中不存在该记录。
任何帮助或建议将不胜感激。谢谢。
INSERT INTO blatchildren
(blatranscriptid, childactivityid, enrollmentDate, enrollmentStatus)
SELECT 2,
'cours000000000004981',
to_date('1/1/2015 12:00:00 AM', 'MM/DD/YYYY HH:MI:SS AM'),
'E'
from dual
where 'cours000000000004981' not in (select childactivityid from blatchildren)
returning id
into :identity
为了测试代码,我一直在 PL/SQL Developer 中运行以下代码:
declare identity number(2);
begin
INSERT INTO blatchildren
(blatranscriptid, childactivityid, enrollmentDate, enrollmentStatus)
VALUES( 2,
'cours000000000004981',
to_date('1/1/2015 12:00:00 AM', 'MM/DD/YYYY HH:MI:SS AM'),
'E')
returning id
into identity;
end;
【问题讨论】:
INSERT..SELECT FROM DUAL..WHERE 不要混合,你不想重复使用唯一键,即使没有 from dual 仍然没有意义 @wero - 是的,多次。 @LukasEder - 我正在使用 PL/SQL 工具进行测试,但在 Visual Studio 中使用。 PLSQL Insert into with subquery and returning clause (Oracle)的可能重复 您愿意在没有 where 子句的情况下运行此 SQL(从 blatchildren 中选择 childactivityid)。相反,如果您运行 select childiactivity from blatchchildren where childactivityid='someid' 然后使用 0 的 sql rowcnt 来决定插入,或者 1 - 不插入。 【参考方案1】:您不能在 PL/SQL 中将 RETURNING
子句与 INSERT .. SELECT
一起使用:
insert_into_clause
values_clause [ returning_clause ]
| subquery
[ error_logging_clause ]
returning_clause
只能与values_clause
一起提供
见:https://docs.oracle.com/database/121/SQLRF/statements_9014.htm#SQLRF55051
更好的方法可能是将UNIQUE
约束添加到blatchildren(childactivityid)
【讨论】:
谢谢,但我不确定在 INSERT 发生之前约束如何防止重复。我查看了对“可能重复”的引用,并按照其中的链接指向 forall。这看起来可能是一个可能的答案,但对于需要条件 where 子句的简单查询来说似乎相当复杂。 “在 INSERT 发生之前” 为什么这很重要?或者更确切地说:为什么你的方法更受欢迎? 也许我误解了你的建议,但我宁愿阻止错误,也不愿编写错误处理程序来捕获它。我是不是误解了你的建议? @Trebor:这是常见的做法。您是否担心性能? 感谢您对 VALUES 子句的澄清。这为我澄清了语法!【参考方案2】:我完全同意 Luka Eder 的回答,但如果您必须使用带有 return 子句的单个查询,它看起来像这样:
variable identity number;
BEGIN
INSERT INTO blatchildren
(blatranscriptid, childactivityid, enrollmentDate, enrollmentStatus)
VALUES ((SELECT 2 from dual where 'cours000000000004981' not in (select childactivityid from blatchildren)),
(SELECT 'cours000000000004981' from dual where 'cours000000000004981' not in (select childactivityid from blatchildren)),
(SELECT to_date('1/1/2015 12:00:00 AM', 'MM/DD/YYYY HH:MI:SS AM') from dual where 'cours000000000004981' not in (select childactivityid from blatchildren)),
(SELECT 'E' from dual where 'cours000000000004981' not in (select childactivityid from blatchildren)))
returning blatranscriptid
into :identity;
END;
/
这里的逻辑,正如 Luka 所说,您必须使用 VALUES 子句才能使 RETURNING 起作用。注意我放在那里的括号数。在 values 子句中进行选择是可能的,我个人从来没有这样写过东西,我相信我只会查询数据库两次。
附言这并不能解决太多问题,您仍然需要进行插入尝试。 但也许它可以节省添加另一个约束,可能你在 id 列上有一个非空约束。
【讨论】:
我说“p.s. 这并不能解决很多问题,您仍然需要尝试插入” - 简短的回答是 Lukas 的回答是关于 oracle 的限制是正确的。 罗伯特,谢谢。我什至没有考虑在 values 子句中使用 SELECT 。尽管它并不漂亮,但它可以防止错误发生,而不仅仅是围绕可能的错误进行编码。虽然我还没有尝试过,但我的猜测是对 values 子句中所有值的单个选择查询也可能有效。谢谢你的想法。以上是关于插入返回 IDENTITY 生成 ORA 00933的主要内容,如果未能解决你的问题,请参考以下文章
为啥 SCOPE_IDENTITY() 不返回我插入的 ID?