【问题标题】:Insert into table if certain values don't exist如果某些值不存在,则插入表中
【发布时间】:2016-11-27 09:37:00
【问题描述】:

我有一个名为 PRODUCTSH2 数据库,每行有 5000 行和 55 列。我目前正在使用PreparedStatement 将值行添加到数据库中,但它不会检查该行是否已经存在。相反,如果列名“id”(VARCHAR 类型)包含某个字母数字字符串,并且列名“id2”(VARCHAR 类型)不某个字母数字字符串,如果列名“raw_yn”(BOOLEAN 类型)包含false。我在准备好的语句中输入的值是通过方法提供的。

here 的问题与我要问的问题非常接近,不同之处在于solution 是基于向空数据库添加行,并确保数据库为空。 H2的创造者评论说:

然后“不存在的地方”确保仅在以下情况下插入此行 表 [TABLE] 为空。

如果满足我的上述 3 个要求(无论 DB 是否为空),我如何调整此代码使其仅执行 INSERT 查询?

目前我有:

 import java.sql. *;
       static final String JDBC_DRIVER = "org.h2.Driver";
       static final String DB_URL = "jdbc:h2:~/myDB";
       static final String USER = "test";
       static final String PASS = "test";
       static final Connection conn = null;
       static final Statement stmt = null;

       public class DataBaseManager {

           public void insertIntoDB(String id1val, String id2val, Boolean raw_yn_val, ...,...) {

               try {
                   Class.forName(JDBC_DRIVER);
                   conn = DriverManager.getConnection(DB_URL, USER, PASS);
                   myStatement = "INSERT INTO PRODUCTS VALUES(?,?,?,..,...)";
                   stmt = conn.prepareStatement(myStatement);
                   stmt.setString(1, id1val);
                   stmt.setString(2, id2val);
                   stmt.setBoolean(3, raw_yn_val);
                   stmt.setString(4,....);
                // Continue up to 55
                   stmt.executeUpdate();
               }

                 [catch&finally blocks]
           }
       }

myStatement 应该改成什么?我很困惑,因为如果我像下面这样使用select 0, 'id1' union,它如何适合我的PreparedStatementstmt.setString(1, id1val); ??。感谢您的帮助。

INSERT INTO PRODUCTS SELECT * FROM(
select 0, 'id1' union                         // <--- How does this fit into Prepared Statement?
select 1, 'id2' union
select 2, 'raw_yn' union
) x where not exists(SELECT * FROM PRODUCTS);  // <--- Ensures only works when empty

更新:

按照 Gord 的建议,我整理了以下代码。如果数据库为空,n 将返回 0。这大约需要 1 分钟才能将 5000 行添加到空数据库。但是,如果有匹配项,则需要将近 5 倍的时间,即使我只是使用 return 而不是使用额外的 INSERT 代码。所以不应该更快吗?

try {
   Class.forName(JDBC_DRIVER);
   conn = DriverManager.getConnection(DB_URL, USER, PASS);
   statement = conn.createStatement();

   String sql = "SELECT COUNT(*) AS n FROM PROPERTIES WHERE id1='" + id1 + "' AND id2='" + id2 + "' AND raw_yn='true'";
   rs = statement.executeQuery(sql);
   rs.next();
   if (rs.getInt("n") == 0) {
    Class.forName(JDBC_DRIVER);
    conn = DriverManager.getConnection(DB_URL, USER, PASS);
    myStatement = "INSERT INTO PROPERTIES VALUES(?,?,?,...)";
    stmt = conn.prepareStatement(myStatement);
    stmt.setString(1, id1);
    stmt.setString(2, id2);
    stmt.setBoolean(3, raw_yn);
    stmt.executeUpdate();
   } else {
    return; // <-- Takes 5x longer to go through ???
   }

  }

    [catch & finally blocks]

【问题讨论】:

  • 由于看起来您将一次插入一行,也许您的insertIntoDB 方法可以执行SELECT COUNT(*) AS n FROM PRODUCTS WHERE ... 来确定所需的行是否已经存在,然后只执行@ 987654340@ 如果不是(即,如果来自SELECT 的行数为零)。
  • 考虑使用暂存临时表 ProductsTemp,然后迁移到每个行检查的最终 Products。但是,检查 55 个值可能很乏味,还是您只想检查 id、id2 和 raw_yn?
  • "但是如何访问 n 来获取计数?" - 你需要做rs.next(); 然后你可以使用rs.getInt("n")rs.getInt(1)跨度>
  • 第二次通过不必执行 INSERT 来节省时间,但 SELECT 将花费更长的时间,因为表包含更多行。您的表是否在 id1id2raw_yn 列上有索引?
  • 我指的是在 H2 表本身的结构中定义的索引。也就是说,如果在 H2 控制台中执行SCRIPT NODATA TABLE "PROPERTIES",输出是否包含id1id2raw_yn 列的CREATE INDEX 语句(或类似语句)?如果没有,您可以使用CREATE INDEX 语句添加它们。

标签: java sql database jdbc h2


【解决方案1】:

考虑使用暂存临时表,将所有数据按原样附加到类似的结构化表 ProductsTemp,然后迁移到最终表 Products,过滤唯一的行。以下是按此顺序合并到您的 Java 代码中的 SQL 语句:

Staging Append (两个语句)

DELETE FROM ProductsTemp;

INSERT INTO ProductsTemp VALUES (?,?,?,..,...);

最终迁移

INSERT INTO Products (id, id2, raw_yn, ...)
SELECT id, id2, raw_yn, ...
FROM ProductsTemp temp
WHERE NOT EXISTS (SELECT 1 FROM Products sub
                   WHERE sub.id = temp.id
                     AND sub.id2 = temp.id2
                     AND sub.raw_yn = temp.raw_yn);

【讨论】:

  • 我想在评论 Parfait 之前全面测试您的建议,感谢您提供此信息。我无法使最后一个查询工作,因为我在 INSERTSELECT 查询中的值太长,以至于我遇到的语法错误很难调试。我做了很多关于临时表的阅读,我计划将来记住它。您的解决方案可能有效,但 Gord 的建议让我很满意。我为您的时间/贡献 +1。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-21
  • 1970-01-01
  • 1970-01-01
  • 2018-09-17
  • 1970-01-01
  • 2012-06-07
  • 1970-01-01
相关资源
最近更新 更多