简体   繁体   English

sql表插入行问题,部分列插入NULL值

[英]Inserting rows in sql table problem, some columns inserted NULL value

I have 2 DB with multiple tables.我有 2 个带有多个表的 DB。 All tables have the same syntax.所有表都具有相同的语法。 Here I have a method that takes name of the table as an argument.在这里,我有一个将表名作为参数的方法。 The table that I try to insert is with 3 columns (int, varchar, int).我尝试插入的表有 3 列(int、varchar、int)。 The problem is, only the first row is inserted, and the 2 and 3 row is NULL, I don't know what is the problem.问题是,只插入了第一行,第2行和第3行是NULL,不知道是什么问题。 Any suggestions, please?请问有什么建议吗?

public void getAndInsertData(String nameOfTable) {

    try {

        Class.forName("com.mysql.jdbc.Driver");

        Connection con1 = DriverManager.getConnection(urlDB1, user1, password1);
        Statement s1 = con1.createStatement();

        Connection con2 = DriverManager.getConnection(urlDB2, user2, password2);
        Statement s2 = con2.createStatement();

        ResultSet rs1 = s1.executeQuery("SELECT * FROM " + nameOfTable);

        ResultSetMetaData rsmd1 = rs1.getMetaData();
        int columnCount = rsmd1.getColumnCount();

        for (int column = 1; column <= columnCount; column++) {

            String columnName = rsmd1.getColumnName(column);
            int columnType = rsmd1.getColumnType(column);

            while (rs1.next()) {

                switch (columnType) {

                    case Types.INTEGER:
                    case Types.SMALLINT:
                    case Types.BIGINT:
                    case Types.TINYINT:

                        int integerValue = rs1.getInt(column);
                        
                        String integerQuery = "insert into " + nameOfTable + " (" + columnName + ") VALUES("
                                + integerValue + ");";
                        s2.executeUpdate(integerQuery);

                        break;

                    case Types.VARCHAR:
                    case Types.NVARCHAR:
                    case Types.LONGNVARCHAR:
                    case Types.LONGVARCHAR:

                        String varcharValue = rs1.getString(column);
                        
                        String varcharQuery = "insert into " + nameOfTable + " (" + columnName + ") VALUES("
                                + varcharValue + ");";
                        s2.executeUpdate(varcharQuery);

                    default:
                        System.out.println("Default");
                        break;

                }

            }
        }

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

Your integerQuery and varcharQuery both insert into datebase table a record with one filled column and blank other columns.您的integerQueryvarcharQuery都将一条记录插入到数据库表中,其中包含一个填充的列和空白的其他列。 Because you provide value to one column only.因为您只为一列提供值。

As The Impaler already mentioned, your loops are at the wrong place.正如 The Impaler 已经提到的,你的循环在错误的地方。 For every record of rs1, you want to insert one record using s2.对于 rs1 的每条记录,您都希望使用 s2 插入一条记录。

You can build a prepared statement first using the metadata and then inject the values: ResultSetMetaData rsmd1 = rs1.getMetaData();您可以首先使用元数据构建准备好的语句,然后注入值: ResultSetMetaData rsmd1 = rs1.getMetaData(); int columnCount = rsmd1.getColumnCount(); int columnCount = rsmd1.getColumnCount();

StringBuffer sql=new StringBuffer("insert into "+nameOfTable+" (");
for (int column = 1; column <= columnCount; column++) {

    String columnName = rsmd1.getColumnName(column);
    if(column>1)
        sql.append(",");
    sql.append(columnName);
}
sql.append(") values (");
for(int i=1;i<=columnCount;i++)
{
    sql.append((i==1?"":",")+ "?");
}
sql.append(")");
System.out.println("Prepared SQL:"+sql.toString());
// sql = insert into nameOfTable (col1,col2,col3) values (?,?,?)
PreparedStatement s2= con2.prepareStatement(sql.toString());

while (rs1.next()) {
    s2.clearParameters();
    for (int column = 1; column <= columnCount; column++) {

        int columnType = rsmd1.getColumnType(column);

        switch (columnType) {

            case Types.INTEGER:
            case Types.SMALLINT:
            case Types.BIGINT:
            case Types.TINYINT:
                s2.setInt(column, rs1.getInt(column));
                break;

            case Types.VARCHAR:
            case Types.NVARCHAR:
            case Types.LONGNVARCHAR:
            case Types.LONGVARCHAR:
                s2.setString(column, rs1.getString(column));
                break;
            default:
                System.err.println("Not supported type for column "+column+" with type:"+columnType);
                s2.setNull(column, columnType);
                break;
        }
    } // end of for loop
    // execute statement once per record in rs1
    s2.executeUpdate();
} // end of while

A few issues:几个问题:

  • Use try-with-resources to make sure the JDBC resources are cleaned up correctly.使用 try-with-resources 确保正确清理 JDBC 资源。

  • No need for a switch statement, because we don't actually need to know the types of the columns.不需要switch语句,因为我们实际上不需要知道列的类型。 The JDBC driver will handle that if you use getObject() and setObject() .如果您使用getObject()setObject() ,JDBC 驱动程序将处理该问题。

  • Only execute one INSERT per row from the source table.源表中的每一行只执行一个INSERT

  • Use batching when inserting a lot of records, for better performance.插入大量记录时使用批处理,以获得更好的性能。

Here is how to do it:这是如何做到的:

try (
    Connection conSource = DriverManager.getConnection(urlDB1, user1, password1);
    Connection conTarget = DriverManager.getConnection(urlDB2, user2, password2);
    Statement stmtSource = conSource.createStatement();
    ResultSet rsSource = stmtSource.executeQuery("SELECT * FROM " + nameOfTable);
) {
    // Build insert statement
    ResultSetMetaData metaData = rsSource.getMetaData();
    int columnCount = metaData.getColumnCount();
    StringBuilder sql = new StringBuilder("INSERT INTO " + nameOfTable + " (");
    for (int column = 1; column <= columnCount; column++) {
        if (column != 1)
            sql.append(", ");
        sql.append(metaData.getColumnName(column));
    }
    sql.append(") VALUES (");
    for (int column = 1; column <= columnCount; column++) {
        if (column != 1)
            sql.append(", ");
        sql.append("?");
    }
    sql.append(")");
    
    // Copy data
    conTarget.setAutoCommit(false);
    try (PreparedStatement stmtTarget = conTarget.prepareStatement(sql.toString())) {
        int batchSize = 0;
        while (rsSource.next()) {
            for (int column = 1; column <= columnCount; column++) {
                // Copy row here. Use switch statement to control the mapping
                // if source and target table columns don't have compatible types.
                // The following statement should work for most types, so switch
                // statement only needs to cover the exceptions.
                stmtTarget.setObject(column, rsSource.getObject(column), metaData.getColumnType(column));
            }
            stmtTarget.addBatch();
            if (++batchSize == 1000) { // Flush every 1000 rows to prevent memory overflow
                stmtTarget.executeBatch();
                batchSize = 0;
            }
        }
        if (batchSize != 0)
            stmtTarget.executeBatch();
    }
    conTarget.commit();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM