【问题标题】:Inserting rows in sql table problem, some columns inserted NULL valuesql表插入行问题,部分列插入NULL值
【发布时间】:2020-09-04 13:33:58
【问题描述】:

我有 2 个带有多个表的数据库。所有表都具有相同的语法。在这里,我有一个将表名作为参数的方法。我尝试插入的表有 3 列(int、varchar、int)。问题是,只插入了第一行,而第2行和第3行都是NULL,不知道是什么问题。有什么建议吗?

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();
    }
}

【问题讨论】:

  • 如果您没有明确地将值放入列中,则使用默认值。如果未指定默认值,则值为NULL
  • 你的循环是由内而外的。 while 应包含 for
  • 我将 for 循环放在了 while 的下方,但还是没有用,您对代码有什么建议吗?我该怎么做?

标签: java mysql sql


【解决方案1】:

您的integerQueryvarcharQuery 都向数据库表中插入一条记录,其中一列已填充,其他列为空白。因为您只为一列提供值。

【讨论】:

  • 我看到了,但我不明白如何放置所有值,有什么建议吗?
  • 使用 StringBuilder 形成列名列表和值列表。
  • 我做了一个列名列表,但我不知道如何在那里制作一个值列表,因为我需要获取该过滤器中的所有列...
【解决方案2】:

几个问题:

  • 使用 try-with-resources 确保正确清理 JDBC 资源。

  • 不需要switch 语句,因为我们实际上不需要知道列的类型。如果您使用 getObject()setObject(),JDBC 驱动程序将处理该问题。

  • 源表中的每一行只执行一个INSERT

  • 在插入大量记录时使用批处理,以获得更好的性能。

这是怎么做的:

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();
}

【讨论】:

  • 这将用于将表内容从 Hana DB 传输到一个 MySQL DB,两者都使用 JDBC,问题是,我知道某些数据类型存在一些差异,这就是我尝试使用 switch 的原因跨度>
  • @RobertVasile Hana DB 需要与 MySQL 不同的 JDBC 驱动程序,不是吗?您应该edit您的问题并添加该信息,即目标数据库是 Hana DB,源数据库是 MySQL。
  • @Abra 这是另一种方式,from Hana to MySQL。 --- 无论如何,由于我们不知道urlDB1urlDB2 的内容,我们 不应该假设它们是相同的数据库风格,即使用相同的 JDBC 驱动程序。
  • 我还不知道,我的导师告诉我们,我们有 2 个 DB,一个是 Hana DB,一个是 MySql,都使用 JDBC,他需要一些东西来将表内容从 Hana 传输到 MySql .他建议切换,因为他说可以是一些不同的数据,例如可以将一些数据存储到String字段中,例如,由于精度,长度等原因,在传输时不会丢失数据。
【解决方案3】:

正如 The Impaler 已经提到的,您的循环位于错误的位置。 对于 rs1 的每条记录,您想使用 s2 插入一条记录。

您可以先使用元数据构建准备好的语句,然后注入值: ResultSetMetaData rsmd1 = rs1.getMetaData(); 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

【讨论】:

  • 我试了一下,他给了我这个异常:java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2)。
  • 你是对的,第一个for循环的结束条件一定是column &lt;= columnCount= 不见了。
  • 现在我有另一个异常说: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'numar' in 'field list' "numar" is the last column name in the table
  • @RobertVasile 似乎您的目标表与源表的列不同。检查表以确保它们具有相同的列、相同的名称和类型。
  • 我添加了一个 System.out.println 来打印准备好的语句(未经测试,希望它打印一些人类可读的 SQL)。如果您希望此代码更具弹性,则应比较两个表的元数据以验证它们具有相同的列定义,并使用差异的详细信息引发异常。
猜你喜欢
  • 2014-04-25
  • 2018-04-13
  • 2016-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多