如果行存在则更新列,如果不存在则更新行

时间:2015-10-31 15:35:30

标签: sqlite jdbc

我有一个表INVENTORY,其中包含2列[product(主键) - quantity]。我想在此表中插入一个含有数量的产品。

public boolean insertPackage(String product, int quantity) 
            throws SQLException, ClassNotFoundException {

        System.out.println("Insert product to Invetory");
        boolean flag=false;
        sq = "INSERT INTO INVENTORY VALUES (?, ?)";

        try {       
            Class.forName(typeDB);
            c = DriverManager.getConnection(path);            
            stm = c.prepareStatement(sq);

            PreparedStatement stm = c.prepareStatement(sq);

            stm.setString(1, product);
            stm.setInt(2, quantity);
            int rowsAffected = stm.executeUpdate();

        } catch (SQLException e) { 
            //There is already a same product in the Inventory
            flag = true;
            System.out.println(e.getMessage());
        } finally {
        if (stm != null)
                    stm.close();
        if (c != null)
                    c.close();
        }     

        return flag; //if the flag is true, then execute insert.
    }

如果返回true,则我搜索此产品,检索数量,然后使用新数量更新表格。我想知道我是否认为这是一种检查如何进行插入的好方法,或者有更好的方法。

2 个答案:

答案 0 :(得分:2)

在您的特定情况下,最简单的解决方案是使用SQLite的INSERT OR REPLACE语法,如下所示:

public static void main(String[] args) {
    String connectionURL = "jdbc:sqlite:";  // in-memory database
    try (Connection conn = DriverManager.getConnection(connectionURL)) {
        // set up test data
        try (Statement st = conn.createStatement()) {
            st.execute("CREATE TABLE INVENTORY (product VARCHAR(10) PRIMARY KEY, quantity INT)");
            st.execute("INSERT INTO INVENTORY (product, quantity) VALUES ('one', 123)");
        }
        System.out.println("Initial state:");
        dumpTable(conn);

        // real code starts here
        String sql = "INSERT OR REPLACE INTO INVENTORY (product, quantity) VALUES (?, ?)";
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setString(1, "two");  // product is new, so it will insert
            ps.setInt(2, 234);
            ps.executeUpdate();
            System.out.println();
            System.out.println("First change:");
            dumpTable(conn);

            ps.setString(1, "one");  // product already exists, so it will replace
            ps.setInt(2, 999);
            ps.executeUpdate();
            System.out.println();
            System.out.println("Second change:");
            dumpTable(conn);
        }
    } catch (Exception e) {
        e.printStackTrace(System.err);
    }       

}

private static void dumpTable(Connection conn) throws SQLException {
    try (
            Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("SELECT product, quantity FROM INVENTORY ORDER BY product")) {
        while (rs.next()) {
            System.out.printf(
                    "product \"%s\" - quantity: %d%n", 
                    rs.getString("product"), 
                    rs.getInt("quantity"));
        }
    }
}

然而,SQLite中的INSERT OR REPLACE实际上只是一个DELETE后跟INSERT,所以另一个解决方案是尝试先执行UPDATE,然后在UPDATE不影响任何行时执行INSERT。 (如果您倾向于进行比插入更多的更新,那可能会更有效。)

public static void main(String[] args) {
    String connectionURL = "jdbc:sqlite:";  // in-memory database
    try (Connection conn = DriverManager.getConnection(connectionURL)) {
        // set up test data
        try (Statement st = conn.createStatement()) {
            st.execute("CREATE TABLE INVENTORY (product VARCHAR(10) PRIMARY KEY, quantity INT)");
            st.execute("INSERT INTO INVENTORY (product, quantity) VALUES ('one', 123)");
        }
        System.out.println("Initial state:");
        dumpTable(conn);

        // real code starts here
        updateQuantity("two", 234, conn);
        System.out.println();
        System.out.println("First update:");
        dumpTable(conn);

        updateQuantity("one", 999, conn);
        System.out.println();
        System.out.println("Second update:");
        dumpTable(conn);

    } catch (Exception e) {
        e.printStackTrace(System.err);
    }       

}

private static void updateQuantity(String theProduct, int newQuantity, Connection conn) throws SQLException {
    int rowsAffected;
    try (PreparedStatement psUpdate = conn.prepareStatement("UPDATE INVENTORY SET quantity=? WHERE product=?")) {
        psUpdate.setInt(1, newQuantity);
        psUpdate.setString(2, theProduct);
        rowsAffected = psUpdate.executeUpdate();
    }
    if (rowsAffected == 0) {
        try (PreparedStatement psInsert = conn.prepareStatement("INSERT INTO INVENTORY (product, quantity) VALUES (?, ?)")) {
            psInsert.setString(1, theProduct);
            psInsert.setInt(2, newQuantity);
            psInsert.executeUpdate();
        }
    }
}

private static void dumpTable(Connection conn) throws SQLException {
    try (
            Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("SELECT product, quantity FROM INVENTORY ORDER BY product")) {
        while (rs.next()) {
            System.out.printf(
                    "product \"%s\" - quantity: %d%n", 
                    rs.getString("product"), 
                    rs.getInt("quantity"));
        }
    }
}

在这两种情况下,我们都会看到:

Initial state:
product "one" - quantity: 123

First update:
product "one" - quantity: 123
product "two" - quantity: 234

Second update:
product "one" - quantity: 999
product "two" - quantity: 234

答案 1 :(得分:1)

这不是检查产品是否存在的好方法,因为:

- 还有许多其他问题可能出错(很多不同的SQLExceptions,不仅仅是PK违规),你最终会得到一个真正的旗帜。

- 你不应该对正常发生的事情使用例外。

- 拖延并捕捉异常很慢。

试试这个:

1)使用count:

从产品中选择INVENTORY
select count(*) from INVENTORY where product = ?

2)如果计数等于0,则执行插入

否则增加数量。