sql >> データベース >  >> RDS >> Mysql

一意の列を持つテーブルへの行の追加:既存のID値と新しく作成されたID値を取得します

    この最初のアプローチでは、バッチINSERTを処理するときのJDBCドライバーの動作については何も想定していません。

    による潜在的なINSERTエラーを回避します
    • 既存のmail_idをテーブルに照会する 現在のデータセットの値
    • 対応するidをメモします それらのmail_idの値 存在する値
    • mail_idを挿入します 存在しない値、およびそれらの(新しい)idを取得します 値、そして
    • 他のテーブルに行を挿入します(inv_table
    try (Connection dbConn = DriverManager.getConnection(myConnectionString, "root", "usbw")) {
        dbConn.setAutoCommit(false);
    
        // test data and setup
        Long aid = 123L;
        List<MailidInvitation> invitationList = new ArrayList<MailidInvitation>();
        invitationList.add(new MailidInvitation(13L));
        invitationList.add(new MailidInvitation(11L));
        invitationList.add(new MailidInvitation(12L));
        // remove stuff from previous test run
        try (Statement s = dbConn.createStatement()) {
            s.executeUpdate("DELETE FROM mail_contacts WHERE mail_id IN (11,13)");
        }
        try (PreparedStatement ps = dbConn.prepareStatement(
                "DELETE FROM inv_table WHERE aid=?")) {
            ps.setLong(1, aid);
            ps.executeUpdate();
        }
    
        // real code starts here
        //
        // create a Map to hold `mail_id` and their corresponding `id` values 
        Map<Long, Long> mailIdMap = new TreeMap<Long, Long>();
        for (MailidInvitation a : invitationList) {
            // mail_id, id (id is null for now)
            mailIdMap.put(a.getId(), null);
        }
    
        // build an SQL statement to retrieve any existing values
        StringBuilder sb = new StringBuilder(
                "SELECT id, mail_id " +
                "FROM mail_contacts " +
                "WHERE mail_id IN (");
        int n = 0;
        for (Map.Entry<Long, Long> entry : mailIdMap.entrySet()) {
            if (n++ > 0) sb.append(',');
            sb.append(entry.getKey());
        }
        sb.append(')');
        String sql = sb.toString();
    
        // run the query and save the results (if any) to the Map
        try (Statement s = dbConn.createStatement()) {
            // <demo>
            System.out.println(sql);
            // </demo>
            try (ResultSet rs = s.executeQuery(sql)) {
                while (rs.next()) {
                    mailIdMap.put(rs.getLong("mail_id"), rs.getLong("id"));
                }
            }
        }
    
        // <demo>
        System.out.println();
        System.out.println("mailIdMap now contains:");
        // </demo>
    
        // build a list of the `mail_id` values to INSERT (where id == null)
        //     ... and print the existing mailIdMap values for demo purposes
        List<Long> mailIdsToInsert = new ArrayList<Long>();
        for (Map.Entry<Long, Long> entry : mailIdMap.entrySet()) {
            String idValue = "";  // <demo />
            if (entry.getValue() == null) {
                mailIdsToInsert.add(entry.getKey());
                // <demo>
                idValue = "null";  
            } else {
                idValue = entry.getValue().toString();
                // </demo>
            }
            // <demo>
            System.out.println(String.format(
                    "    %d - %s", 
                    entry.getKey(),
                    idValue));
            // </demo>
        }
    
        // batch insert `mail_id` values that don't already exist
        try (PreparedStatement ps = dbConn.prepareStatement(
                "INSERT INTO mail_contacts (mail_id) VALUES (?)", 
                PreparedStatement.RETURN_GENERATED_KEYS)) {
            for (Long mid : mailIdsToInsert) {
                ps.setLong(1, mid);
                ps.addBatch();
            }
            ps.executeBatch();
            // get generated keys and insert them into the Map
            try (ResultSet rs = ps.getGeneratedKeys()) {
                n = 0;
                while (rs.next()) {
                    mailIdMap.put(mailIdsToInsert.get(n++), rs.getLong(1));
                }
            }
        }
    
        // <demo>
        System.out.println();
        System.out.println("After INSERT INTO mail_contacts, mailIdMap now contains:");
        for (Map.Entry<Long, Long> entry : mailIdMap.entrySet()) {
            System.out.println(String.format(
                    "    %d - %s", 
                    entry.getKey(),
                    entry.getValue()));
        }
        // </demo>
    
        // now insert the `inv_table` rows
        try (PreparedStatement ps = dbConn.prepareStatement(
                "INSERT INTO inv_table (mid, aid) VALUES (?,?)")) {
            ps.setLong(2, aid);
            for (MailidInvitation a : invitationList) {
                ps.setLong(1, mailIdMap.get(a.getId()));
                ps.addBatch();
            }
            ps.executeBatch();
        }
        dbConn.commit();
    }
    

    結果のコンソール出力は次のようになります:

    SELECT id, mail_id FROM mail_contacts WHERE mail_id IN (11,12,13)
    
    mailIdMap now contains:
        11 - null
        12 - 1
        13 - null
    
    After INSERT INTO mail_contacts, mailIdMap now contains:
        11 - 15
        12 - 1
        13 - 16
    

    一部のJDBCドライバーでは、バッチ内の1つ以上のステートメントが失敗した場合でも、バッチを続行できます。たとえば、MySQL Connector / Jでは、オプションはcontinueBatchOnErrorです。 これはtrueです デフォルトでは。そのような場合、別のアプローチは、すべてのmail_idを挿入してみることです。 値を確認し、バッチによって返される更新カウントを確認します。 INSERTが成功すると、UpdateCountが1になりますが、既存のmail_idが原因でINSERTが失敗すると EXECUTE_FAILEDを返します (-3)。次に、(新しい)idを取得できます .getGeneratedKeys()を介した成功したINSERTの値 、次にSELECTステートメントの作成に進み、戻ってidを取得します。 mail_idの値 すでに存在するエントリ。

    したがって、このようなコード

    // create a Map to hold `mail_id` and their corresponding `id` values 
    Map<Long, Long> mailIdMap = new TreeMap<Long, Long>();
    for (MailidInvitation a : invitationList) {
        // mail_id, id (id is null for now)
        mailIdMap.put(a.getId(), null);
    }
    
    // try INSERTing all `mail_id` values
    try (PreparedStatement ps = dbConn.prepareStatement(
            "INSERT INTO mail_contacts (mail_id) VALUES (?)", 
            PreparedStatement.RETURN_GENERATED_KEYS)) {
        for (Long mid : mailIdMap.keySet()) {
            ps.setLong(1, mid);
            ps.addBatch();
        }
        int[] updateCounts = null;
        try {
            updateCounts = ps.executeBatch();
        } catch (BatchUpdateException bue) {
            updateCounts = bue.getUpdateCounts();
        }
        // get generated keys and insert them into the Map
        try (ResultSet rs = ps.getGeneratedKeys()) {
            int i = 0;
            for (Long mid : mailIdMap.keySet()) {
                if (updateCounts[i++] == 1) {
                    rs.next();
                    mailIdMap.put(mid, rs.getLong(1));
                }
            }
        }
    }
    
    // <demo>
    System.out.println("mailIdMap now contains:");
    // </demo>
    
    // build a SELECT statement to get the `id` values for `mail_id`s that already existed
    //     ... and print the existing mailIdMap values for demo purposes
    StringBuilder sb = new StringBuilder(
            "SELECT id, mail_id " +
            "FROM mail_contacts " +
            "WHERE mail_id IN (");
    int n = 0;
    for (Map.Entry<Long, Long> entry : mailIdMap.entrySet()) {
        String idValue = "";  // <demo />
        if (entry.getValue() == null) {
            if (n++ > 0) sb.append(',');
            sb.append(entry.getKey());
            // <demo>
            idValue = "null";  
        } else {
            idValue = entry.getValue().toString();
            // </demo>
        }
        // <demo>
        System.out.println(String.format(
                "    %d - %s", 
                entry.getKey(),
                idValue));
        // </demo>
    }
    sb.append(')');
    String sql = sb.toString();
    
    // <demo>
    System.out.println();
    System.out.println(sql);
    // </demo>
    

    次のようなコンソール出力を生成します:

    mailIdMap now contains:
        11 - 17
        12 - null
        13 - 19
    
    SELECT id, mail_id FROM mail_contacts WHERE mail_id IN (12)
    

    残りのプロセスは以前と同じです:

    • 残りのmailIdMapに入力します エントリ、および
    • idを使用して他のテーブルのINSERTを処理します mailIdMapの値 。



    1. mysqlでシノニムを作成する方法

    2. 1日に複数のレコードを選択するにはどうすればよいですか?

    3. Mysql-2つのJsonオブジェクトを比較する方法は?

    4. Oracleで複数の行をコンマ区切りのリストに結合するにはどうすればよいですか?