如何根据 JDBC Result Set 创建表

Posted

技术标签:

【中文标题】如何根据 JDBC Result Set 创建表【英文标题】:How to create table based on JDBC Result Set 【发布时间】:2012-07-01 08:31:39 【问题描述】:

我正在构建一个报告工具,我需要对远程数据库执行查询并将结果集存储在我自己的数据库中(因为我没有远程数据库的写权限,而且我需要缓存结果以防止进一步执行)。此外,我需要这种能力,因此我可以将两个结果集连接在一起,并根据生成的结果生成结果。

现在,我的问题是我不知道如何基于 jdbc ResultSet 创建 TABLE。是否有任何开源工具或脚本可以处理这个问题?

我的应用程序基于 Spring 3.1.0 并使用 JDBC 来查询本地和远程数据库。我要存储结果的本地数据库是 mysql 5.5.20。 (这是存储在 MySQL 中的好主意吗?它提供了足够的性能吗?)

【问题讨论】:

其实我还需要在建表后将结果集插入到生成的表中。 How can I use JDBC to copy schema from one database to another without using Apache DDLUtils?的可能重复 【参考方案1】:

我们可以从结果集中提取最近匹配结构并构造一个表。 但是这不可能是精确的副本,在表名、键、引擎类型、字段是否可以为空等方面。

以下代码 sn-p 可帮助您以某种方式继续获得适当的结果。

String sql = "select * from visitors";
ResultSet rs = stmt.executeQuery( sql );
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
String tableName = null;
StringBuilder sb = new StringBuilder( 1024 );
if ( columnCount > 0 )  
    sb.append( "Create table " ).append( rsmd.getTableName( 1 ) ).append( " ( " );

for ( int i = 1; i <= columnCount; i ++ ) 
    if ( i > 1 ) sb.append( ", " );
    String columnName = rsmd.getColumnLabel( i );
    String columnType = rsmd.getColumnTypeName( i );

    sb.append( columnName ).append( " " ).append( columnType );

    int precision = rsmd.getPrecision( i );
    if ( precision != 0 ) 
        sb.append( "( " ).append( precision ).append( " )" );
    
 // for columns
sb.append( " ) " );

System.out.println( sb.toString() );

执行以上部分代码,打印出如下字符串:

Create table visitors ( ip VARCHAR( 6 ), bro VARCHAR( 6 ) )

希望这可以帮助您继续前进。

可以在以下位置找到类似的示例:Create a table using ResultSet ???

更新 1

我该如何处理只存在于一个数据库中而不存在于另一个数据库中的类型

仅依赖于客户端应用程序的结果集时,您无能为力。主选择查询应该始终从 geometryaddress 等复合数据类型中选择适当的数据。示例select addess.city, address.zipcode, x( geometry_column ), y( geometry_column )

举个geometry数据类型的例子: MySQL 对其Spatial Support 有定义。但我不确定它们与SQL Server's implementation of Spatial Data 相比有多好。

geometry 是一种复合数据类型,因此无法通过直接查询来检索。 您需要从这些数据列解析数据并以可读可识别数据格式返回的依赖函数。示例:@ 987654333@ 使用 JAVA 将 ResultSet 从 select g from geom 转换为 create table 语句将导致列 g 的数据类型为 unknwon

Create table geom ( g UNKNOWN )

g 列上使用x(g)y(g) 坐标函数将返回正确且可接受的数据类型。 查询 select x(g), y(g) from geom 将转换为

Create table  ( x(g) DOUBLE( 23, 31 ), y(g) DOUBLE( 23, 31 ) ) 

更新 2: 可以使用关系结合多个表来生成结果集。结果集字段也有可能由表达式及其别名组成。因此,生成的列字段或别名的数据类型是动态确定的。元数据不知道查询中的表、列名及其原始/父数据类型的确切名称。

所以,不可能得到

    表的单一名称并使用它。 父列的数据类型并使用它。

注意:这也适用于所有其他跨数据库特定数据类型,如 NVARCHAR 等。 但是,请参考this posting for an alternative to NVARCHAR usage in MySQL。

在尝试这种动态数据迁移之前,客户端应用程序应该有责任了解等效的数据类型并相应地使用它们。

另外,请参阅Data types and ranges for Microsoft Access, MySQL and SQL Server 了解更多信息。

【讨论】:

非常感谢@Ravinder!这就是答案。但是,我如何处理只存在于一个数据库中而不存在于另一个数据库中的类型(请记住,我们需要一种始终有效的通用方法)?例如,MSSQLServer 有一些 MySQL 没有的几何类型。 再次感谢您更新您的回答。但我之前的问题的另一方面是处理数据库供应商之间的不同数据类型。例如,SQLServer 有 NVARCHAR 数据类型,但 MySQL 不提供这种类型。不同数据库类型之间映射的解决方案是什么?因为 JDBC MetaData 将提供供应商特定的数据,而不是标准数据类型。 谢谢!但是没有提供通用的解决方案,我认为目前不存在这样的东西,需要一个脚本来在不同的数据库供应商之间映射这些类型。【参考方案2】:

也许这有点棘手,但我认为它可能会对你有所帮助。

JDBC ResultSet 对象有一个getMetaData() 方法,该方法返回一个ResultSetMetaData 对象,其中包含列名和列类型等。你可以这样做:

ResultSet rs;
String strSQL;

...

strSQL = "create table tbl ("
for(i=0;i<rs.getMetaData().getColumnCount(),i++) 
    if(i>0)
        strSQL += ", "
    strSQL += rs.getMetaData().getColumnName(i) 
           + " " 
           + rs.getMetaData().getColumnType(i);

strSQL+= ")"

....

您可以通过这种方式构造一个包含您需要的列的有效 SQL DML。之后,剩下的就是填充表格。

希望对你有所帮助。

【讨论】:

【参考方案3】:

您可能拥有基于执行选择查询的 ResultSet。现在,我们可以执行单个查询来创建表,而不是获取 ResultSet 然后遍历它来创建表。

您的原始查询:

select * from table_name

不要执行这个和迭代,而是执行这个

create table new_table_name as (select * from table_name)

【讨论】:

【参考方案4】:

作为 sepcified here,您可以像这样在普通 SQL 中执行此操作:

CREATE TABLE artists_and_works
  SELECT artist.name, COUNT(work.artist_id) AS number_of_works
  FROM artist LEFT JOIN work ON artist.id = work.artist_id
  GROUP BY artist.id;

【讨论】:

也许我应该更具体一些。正如我告诉你的,我正在构建一个报告工具,所以查询是未知的,最终用户将创建查询。现在,目前我的程序执行这个查询,现在我有 JDBC ResultSet,但我想将它存储在我的本地数据库中,所以我应该首先创建表。您的解决方案对我不利,因为我的查询应该在 远程数据库 上执行,现在我应该处理 JDBC ResultSet。 现在我看到该表来自另一个数据库 - 如果它没有太大变化,并且不是太大 - 您可以将相关表复制到您的数据库并运行查询跨度> 不,不可能,因为我会处理百万条记录的数据库,但是用户查询的结果不到几百条记录。那么,你有没有更好的解决方案? 考虑到远程数据库可以是可以具有 JDBC 连接的任何类型的数据库(例如 SQLServer、Oracle、PostgreSQL),您从远程数据库复制整个表的解决方案是什么? 【参考方案5】:

如果你想要一个通用的解决方案来处理数据库之间不同但在java中类型相同的数据,你可以使用JDBCType。 只需采用 Ravinder Reddy 解决方案并更改此行:

String columnType = rsmd.getColumnTypeName( i );

String columnType = JDBCType.valueOf(rsmd.getColumnType(i)).getName();

希望对你有帮助。

【讨论】:

以上是关于如何根据 JDBC Result Set 创建表的主要内容,如果未能解决你的问题,请参考以下文章

mysql表创建好后添加外键

Java与mysql数据库编程中遇见“Before start of result set at com.mysql.jdbc.SQLError.createSQLException” 的解决办法

如何使用 Spring JDBC Framework 将“null”时间戳插入 DB2 数据库

java.sql.SQLException: Before start of result set常见场景

使用 pandas 数据透视表创建子图

SQL - 分区或循环从主表创建子表[关闭]