CSV 上的 SQL 使用 HSQLDB JDBC 驱动程序

Posted

技术标签:

【中文标题】CSV 上的 SQL 使用 HSQLDB JDBC 驱动程序【英文标题】:SQL on CSV using HSQLDB JDBC Driver 【发布时间】:2011-09-22 08:54:05 【问题描述】:

我有一个预生成的 CSV 文件,我需要在该文件上运行 SQL 查询。我一直在寻找不同的开源解决方案(例如 CsvJdbc、xlSQL 等),但还没有真正找到任何令人满意的解决方案。

CsvJdbc 无法识别 ORDER BY、GROUP BY 等 xlSQL 仅在 XLS 文件上运行,而不是 CSV(或者我无法让它与 CSV 一起运行。有人知道怎么做吗?)。此外,它不再处于开发或支持状态。

我在某处读到 HSQLDB 支持查询 CSV 文件,但我无法正常工作。这是我到目前为止所做的:

如果我使用 HSQLDB 创建一个 CSV 文件,那么它能够成功执行查询。这是代码:

String driver = "org.hsqldb.jdbcDriver";
Driver d = (Driver) Class.forName(driver).newInstance();
String protocol = "jdbc:hsqldb:file";
final String url = "jdbc:hsqldb:file:/C:/Users/varun.achar/Documents";

final StringBuilder createTable = new StringBuilder();
createTable.append("CREATE TEXT TABLE currency (");
createTable.append("id INT PRIMARY KEY, name VARCHAR)");
final StringBuilder linkTable = new StringBuilder();
linkTable.append("SET TABLE currency SOURCE ");
linkTable.append("\"/currencies.csv");
linkTable.append(";ignore_first=true;all_quoted=true\"");
Connection conn = DriverManager.getConnection(url, "sa", "");
Statement stm = conn.createStatement();
stm.execute(createTable.toString());
stm.execute(linkTable.toString());
ResultSet resultSet = stm.executeQuery("SELECT * FROM CURRENCY");
if (resultSet != null) 
    while (resultSet.next()) 
        System.out.println("CURRENCY = " + resultSet.getString(2));
    

conn.close();

但是当我删除文件并再次运行时,同样的事情不起作用!我收到错误

表已存在:语句 [CREATE TEXT TABLE 货币] 中的 CURRENCY

另外,如果我有一个预先存在的 csv 文件(格式正确,因为我能够使用 CsvJDBC 运行一个简单的 select 语句)然后我得到错误

未找到表:语句 [SET TABLE rms] 中的 RMS

代码

final StringBuilder linkTable = new StringBuilder();
linkTable.append("SET TABLE rms SOURCE ");
linkTable.append("\"C:/myreports/temp/user/1316083232009/rms.csv");
linkTable.append(";ignore_first=true;all_quoted=true\"");
Driver d = (Driver) Class.forName(driver).newInstance();
System.out.println("Driver was successfully loaded.");
String protocol = "jdbc:hsqldb:file";
String database = "C:\\myreports\\temp\\user\\1316083232009\\rms.csv";
String url = protocol + ":" + database;
con = DriverManager.getConnection(url);
stm = con.createStatement();
stm.execute(linkTable.toString());
resultSet = stm.executeQuery(testSQLStatement());
if (resultSet != null) 
    while (resultSet.next()) 
        System.out.println("FULL NAME = "+ resultSet.getString("usr_FULL_NAME"));
    

有人可以解释一下吗?

谢谢

【问题讨论】:

【参考方案1】:

一个 HSQLDB 数据库可以有很多表,包括几个 TEXT 表。您似乎认为每个文本表必须有一个数据库,但事实并非如此。

数据库路径不是目录。它也不是 CSV 文件。在您的第一个示例中,您应该指定一个数据库名称,如下所示:

final String url = "jdbc:hsqldb:file:/C:/Users/varun.achar/Documents/mydb";

第二个例子也是如此。

数据库由几个以您指定的名称开头的文件组成。在此示例中,您将拥有mydb.propertiesmydb.script 等。

CREATE TEXT TABLE ... 语句为表创建元数据。此表元数据保存在数据库中。

然后第一个示例将起作用。如果你删除 CSV 文件,然后打开数据库,'CREATE TEXT TABLE' 语句仍然存储在数据库中,因此当你再次尝试创建同一个表时它会报错。

如果您有一个预先存在的 CVS 文件,您仍然需要以 CREATE TEXT TABLE ... 开头,然后使用 SET TABLE 语句将其与 CVS 链接,方法与第一个示例相同。

【讨论】:

谢谢..我也想通了..:D 虽然我想问一下,hsqldb 是在应用 where 子句等之前将整个文件读入内存,还是有一种机制可以直接对文件执行这些操作? 它读取整个文件一次以创建索引。然后它读取选择性行。主键列有一个自动索引。如果 WHERE 子句位于不同的列上,则需要在该列上创建索引。在 SET TABLE 语句之前创建索引更快。 谢谢。那真的很有帮助。 :) SET TABLE ABC SOURCE .. 如果 CSV 数据没有像 2011-11-05 12:00:00 这样格式化,则不会成功。您需要将列定义为 BIGINT,然后运行 ​​WHERE START_DATE > (TIMESTAMP '2011-11-05 12:00:00' - TIMESTAMP '1970-01-01 00:00:00') SECOND / 1000 等查询以使用索引。要将毫秒显示为时间戳,请添加值:TIMESTAMP '1970-01-01 00:00:00' + CAST(START_DATE / 1000 AS INTERVAL SECOND)

以上是关于CSV 上的 SQL 使用 HSQLDB JDBC 驱动程序的主要内容,如果未能解决你的问题,请参考以下文章

java.sql.SQLException: SQL 语句在 org.hsqldb.jdbc.JDBCUtil.sqlException 处关闭

如何使用 HSQLDB API 的 org.hsqldb.jdbc.JDBCConnection 类

如何使用 JDBC 工具访问 hsqldb 数据库?

HSQLDB:奇怪的“唯一约束或索引违规”,从CSV读取数据

比较 hsqldb 和 mysql

原因:org.hsqldb.HsqlException: invalid statemnet - 导入 CSV 数据时需要文本表