【问题标题】:Apache Derby: how can I do "insert if not exists"?Apache Derby:我该如何做“如果不存在则插入”?
【发布时间】:2010-09-29 07:00:17
【问题描述】:

我给Apache Derby,又名JavaDB 一个旋转。在插入可能已经存在的记录时,我似乎无法解决重复键问题。是否有相当于“insert if not exists”或“merge”的德比?

同样,有没有办法做类似“drop table foo if exists”的事情?

【问题讨论】:

  • 如果您不喜欢 Derby,不妨试一试 H2 - 它是 faster,并且有一个非常漂亮且简单的 MERGE 动词。

标签: java sql derby


【解决方案1】:

我从未使用过 apache derby,但是一个完全独立于数据库的通用解决方案如下:

要将值 'a' 和 'b' 插入到表 foo 中(列名为 A、B),但仅限于值不存在的地方,请尝试类似

INSERT INTO foo (  
  SELECT 'a' as A, 'b' as B
  FROM foo  
  WHERE  
    A = 'a' AND B = 'b'  
  HAVING count(*)=0  
 )

这可能需要针对特定​​的 dbms 进行调整,但想法是插入仅在没有值时才返回值的选择结果。

这是创建幂等 sql 脚本(第二次运行时不执行任何操作)的有用技巧。但是,在生产代码中使用它时要小心,因为 HAVING count(*)=0 在大型表上可能会非常慢。

【讨论】:

  • 这是一个不错的技巧。可以使它与多行一起使用吗?可能,使用 VALUES 语法,但我不确定。
  • 也适用于 HSQLDB!非常好!
  • 使用MERGE 实际上要好得多;看看这个答案:stackoverflow.com/questions/2609996/…
  • 这会导致Error code 0, SQL state XJ001: Java exception: '8: java.lang.ArrayIndexOutOfBoundsException'.作为批处理使用
【解决方案2】:

我使用 PostgreSQL 数据库的标准方法如下:

INSERT INTO foo ( col1, col2, col3, ... )
SELECT 'col1 value', 'col2 value', 'colc value', ...
WHERE NOT EXISTS (
  SELECT 0
  FROM foo
  WHERE col1 = 'col1 value'
  ...
)

不确定它的可移植性或严格符合 ANSI 的程度。外部 SELECT 语句中缺少的 FROM 子句尤其可能是非标准的。不过还是试试吧。

【讨论】:

    【解决方案3】:

    对此没有本机支持,为了解决这个问题,我正在使用 eclipse-link,eclipse-link 将尝试创建表并忽略尝试创建已经存在的表时出现的任何错误。

    如果您进行架构更改,您可以告诉 eclipse 链接在创建表之前删除它们。

    【讨论】:

      【解决方案4】:

      我正在使用这个解决方案,但只有在您了解数据库视图中的重复项用户视图中的重复项之间的区别时,您才必须使用它

      • 数据库视图中的重复项是具有相同主键的两条记录
      • 用户视图中的重复项是所有字段都相同的两条记录

            while (ResultSet.next()) {
            try {
            PreparedStatement insertion = myConn.prepareStatement("insert into table values (?)");
            insertion .setString(1, "test");
            insertion .executeUpdate();           
            } catch (SQLException e) {
                if(e.getSQLState().equals("23505"))//Found duplicate from database view
                 {continue;}//ignore duplicate and continue with the insert statement
                else{try {                           
                      throw e;
                } catch (Exception ex) {  
                    }
                  }
                }
              }
        

      【讨论】:

      • 第二个 try-catch 不会确保不会抛出任何东西。?本质上,整个 catch(SQLException) 块的行为与它完全为空时的行为完全相同
      【解决方案5】:

      支持 SQL:2003 MERGE 语句的请求在 Derby 错误跟踪器中记录为 https://issues.apache.org/jira/browse/DERBY-3155

      您可以为该问题投票,或者更好的是,贡献一个实现!

      否则,我所知道的唯一解决方案需要先选择行以查看它是否存在,或者插入它并捕获异常,正如其他人所指出的那样。

      您可以将此逻辑打包到数据库过程中,使其更易于执行。

      【讨论】:

      • 呃。 SQL:2003 MERGE 是可怕的。标准且灵活,但要插入一行的文字太多了!
      • 我同意...太多重复(上面的经典技巧也是如此。)我想知道是否有标准替代方案,因为如果我当时找到了,我会要求功能而是那个。
      【解决方案6】:

      我遇到了同样的问题,我得到了这个在 Derby 上只有一个值/列的插入。 (我从来没有用更多的时间来测试它,但我没有理由认为它不应该):

      INSERT INTO my_table (my_column)
          (SELECT 'new_value_to_insert'
          FROM my_table
          WHERE my_column = 'new_value_to_insert' 
          HAVING count(*)=0)
      

      【讨论】:

      • 完美!我知道这些是与问题不同的数据库,但此解决方案适用于 PostgreSQL 和 HSQLDB。
      【解决方案7】:

      Derby 在 10.11 中实现了 MERGE:https://db.apache.org/derby/docs/10.11/ref/rrefsqljmerge.html
      请注意,您需要在使用之前将您的数据库升级到 10.11:https://db.apache.org/derby/docs/10.11/devguide/cdevupgrades.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-09-17
        • 2014-06-11
        • 1970-01-01
        • 2017-04-24
        • 1970-01-01
        • 2016-05-15
        • 1970-01-01
        • 2015-03-31
        相关资源
        最近更新 更多