PL/SQL 插入使用多个选择和减号运算符

Posted

技术标签:

【中文标题】PL/SQL 插入使用多个选择和减号运算符【英文标题】:PL/SQL insert using multiple selects and minus operator 【发布时间】:2016-08-19 15:04:50 【问题描述】:

以下作品:

INSERT INTO BASE_TABLE
(
    req, 
    desc,
    ver
)
    SELECT * FROM UPDATE_TABLE
minus
    SELECT req, desc, ver FROM BASE_TABLE;

但是,这会导致错误(只是尝试再插入一个字段:'key'):

INSERT INTO BASE_TABLE
(
    req, 
    desc,
    ver,
    key        
)
    SELECT * FROM UPDATE_TABLE
minus
    SELECT req, desc, ver FROM BASE_TABLE,
    SELECT CONCAT(req, ver) FROM UPDATE_TABLE;

错误:

PL/SQL:ORA-00903:无效的表名

尝试通过从 UPDATE 表中选择尚未在 BASE_TABLE 中的所有内容来将行插入到 BASE_TABLE 中。只是想添加“关键”字段。

最后一个 SELECT 似乎不合适并导致此错误。 'SELECT ...减去SELECT ...'是否等于一条语句,因此需要将第三条SELECT语句分开?但是怎么做呢?

【问题讨论】:

看看MERGE - 当您需要比较INSERT 的两个表时,它可能会好得多。 一些注意事项/问题:首先,您将不能使用DESCKEY 作为列名(它们是无效的对象名,因为它们是Oracle 保留字)。在您的实际数据中,您可能有其他名称,但对于测试 DESCKEY 将不起作用。然后,在 Oracle 中 concat() 非常有限(例如它只需要两个参数),你最好使用 || 操作符来做同样的事情。那么,你的reqver是什么数据类型呢?如果不是字符数据类型,Oracle会隐式转换,是你想要的吗? 另外,你连接 req 和 ver 没有分隔符;那是一种奇怪的钥匙。 req=1,ver=23 将与 req=12,ver=3 具有相同的密钥 - 这是您需要的吗? 感谢 mathguy,我看看 MERGE。把真名拿出来,当然是保留字了:)req是唯一值,这里应该不错。 我发布了两个解决方案(它们完全不同,所以我没有将它们显示为一个答案)。其中一个不使用 MERGE,它只是修复了您最初的尝试。 (我认为 - 我没有测试它。) 【参考方案1】:

要使其按原样工作,您的最后一个“SELECT”实际上应该转到外部查询,如下所示:

INSERT INTO BASE_TABLE
(
    req, 
    desc,
    ver,
    key        
)
    SELECT req, desc, ver, CONCAT(req, ver)
    FROM 
    ( SELECT * FROM UPDATE_TABLE
      minus
      SELECT req, desc, ver FROM BASE_TABLE
    );

注意:这是一个“懒惰”的解决方案,应该没有SELECT *,列名应该完整拼写。我只是按照您的指示... 现在,UPDATE_TABLE 应该具有正确的列数、正确的名称和正确的顺序,因为您说您的第一个查询有效(否则它将无法正常工作)。但是如果以后你在UPDATE_TABLE中添加一列,SELECT *的查询将不再起作用,但全列名的查询不会受到影响。

【讨论】:

此方法出错:PL/SQL: ORA-01789: 查询块的结果列数不正确 对不起,是的 - 让我来解决它。 (减号仍然需要一个子查询!) 当我看到“减号”运算符时,我的眼睛抽搐了一下。第一次使用 pl/sql。 真的是 SQL,而且是标准的 SQL。 MINUS 操作是基本的集合论操作,应该存在于任何关系数据库和语言标准中。 还没有真正遇到过。我在这里向另一位开发人员展示了这个问题,他也没有看到。也许不常见?也许您的合并方法是解决此类问题的干净方法?【参考方案2】:

基于 mus shou 的两个选择包含相同数量和类型的列

尝试使用

SELECT req, desc, ver FROM UPDATE_TABLE
 minus
SELECT req, desc, ver FROM BASE_TABLE

【讨论】:

【参考方案3】:

MERGE 解决方案:插图

文档在这里:https://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9016.htm

我创建了两个小桌子来进行说明。请参阅我对原始帖子的评论:desckey 是保留字,因此它们不能用作列名,我相应地更改了它们。我使用|| 运算符进行连接并显式转换为字符数据类型(VARCHAR2)。

创建小型测试表:

create table  base_table ( req, dscr, ver, ky ) as 
       select 1, 'alpha', 235, '1235' from dual union all
       select 2, 'beta' , 33 , '233'  from dual
;
select * from base_table;

       REQ DSCR         VER KY 
---------- ----- ---------- ----
         1 alpha        235 1235
         2 beta          33 233

create table update_table (req, dscr, ver) as
   select 1, 'alpha', 235 from dual union all
   select 5, 'rho'  , 444 from dual
;
select * from update_table;

       REQ DSCR         VER
---------- ----- ----------
         1 alpha        235
         5 rho          444

MERGE解决方案和结果:

merge into base_table   b
    using  update_table u
    on     (b.req = u.req and b.dscr = u.dscr and b.ver = u.ver)
  when not matched then
    insert (   req,   dscr,   ver, ky                               )
    values ( u.req, u.dscr, u.ver, to_char(u.req) || to_char(u.ver) )
;

select * from base_table;

       REQ DSCR         VER KY 
---------- ----- ---------- ----
         1 alpha        235 1235
         2 beta          33 233 
         5 rho          444 5444

【讨论】:

以上是关于PL/SQL 插入使用多个选择和减号运算符的主要内容,如果未能解决你的问题,请参考以下文章

类似于 PL/SQL 中的 += 或 .= 的运算符?

在 pl/sql 块中使用 OR 运算符匹配行中的值

=> 在 oracle pl sql.is 和调用运算符中是啥意思?

SonarQube pl / sql规则plsql:S1764问题

pl/sql 美元运算符?

Oracle Pl/SQL 中用户定义运算符背后的动机