3

问题概要: 当尝试在 Java 中使用 SQLite 数据库执行 SQL 查询时,SQL 语句无法从 execute() 或 executeQuery() 方法返回。换句话说,系统在执行这条 SQL 语句时“挂起”。

问题: 我在解释为​​什么 ResultSet 永远不会“返回”时做错了什么?

故障排除 我试图缩小问题范围,问题似乎出在 Java 的 execute() 或 executeQuery() 上。ResultSet 似乎永远不会返回。例如,我尝试直接在 SQLite 中执行完全相同的查询(即使用 SQLite DB 管理器)。查询(在 Java 之外)在大约 5 毫秒内执行并返回有效的结果集。

注意:不会引发异常。该系统似乎只是“挂起”并且在手动杀死之前变得无响应。(等待超过 10 分钟。)

代码: 我对这段代码进行了大量编辑,以使问题更易于查看。(在生产中,这使用准备好的语句。但是,错误发生在两种方法中——直接声明和准备好的声明版本。)

基本上,SELECT 返回单个数据库项目,以便用户可以查看该项目。

Statement st = conn.createStatement() ;
ResultSet rs = st.executeQuery("SELECT DISTINCT  d1.id, d1.sourcefullfilepath, " +
    "d1.sourcefilepath, d1.sourcefilename, d1.classificationid, d1.classid, " +
    "d1.userid  FROM MatterDataset,   (SELECT MatterDataset.id, " + 
    "MatterDataset.sourcefullfilepath, MatterDataset.sourcefilepath, " +
    "MatterDataset.sourcefilename, MatterDataset.matterid   , " +
    "DocumentClassification.classificationid, DocumentClassification.classid," +
    " DocumentClassification.userid   FROM MatterDataset    " +
    "LEFT JOIN DocumentClassification ON " +
    "DocumentClassification.documentid = Matterdataset.id    " +
    "WHERE (   DocumentClassification.classid = 1 OR  " +
    "DocumentClassification.classid = 2 )   AND " +
    "DocumentClassification.userid < 0    AND " +
    "MatterDataset.matterid = \'100\'   ) AS d1    " +
    "LEFT JOIN PrivilegeLog ON " +
    "d1.id = PrivilegeLog.documentparentid AND " +
    "d1.matterid = PrivilegeLog.matterid  " +
    "WHERE PrivilegeLog.privilegelogitemid IS NULL  " +
    "AND MatterDataset.matterid = \'100\'   " +
    "ORDER BY d1.id  LIMIT 1 ;") ;

配置: Java 6、JDBC 驱动程序 = Xerial sqlite-jdbc-3.7.2、SQLite 3、Windows

更新 次要修订:当我继续使用此功能时,将 MIN(d1.id) 添加到 SQL 语句的开头至少会返回一个 ResultSet(而不是“挂起”)。但是,这并不是我真正想要的,因为 MIN 消除了 LIMIT 函数。

Statement st = conn.createStatement() ;
ResultSet rs = st.executeQuery("SELECT DISTINCT  MIN(d1.id), d1.id,
    d1.sourcefullfilepath, " +
    "d1.sourcefilepath, d1.sourcefilename, d1.classificationid, d1.classid, " +
    "d1.userid  FROM MatterDataset,   (SELECT MatterDataset.id, " + 
    "MatterDataset.sourcefullfilepath, MatterDataset.sourcefilepath, " +
    "MatterDataset.sourcefilename, MatterDataset.matterid   , " +
    "DocumentClassification.classificationid, DocumentClassification.classid," +
    " DocumentClassification.userid   FROM MatterDataset    " +
    "LEFT JOIN DocumentClassification ON " +
    "DocumentClassification.documentid = Matterdataset.id    " +
    "WHERE (   DocumentClassification.classid = 1 OR  " +
    "DocumentClassification.classid = 2 )   AND " +
    "DocumentClassification.userid < 0    AND " +
    "MatterDataset.matterid = \'100\'   ) AS d1    " +
    "LEFT JOIN PrivilegeLog ON " +
    "d1.id = PrivilegeLog.documentparentid AND " +
    "d1.matterid = PrivilegeLog.matterid  " +
    "WHERE PrivilegeLog.privilegelogitemid IS NULL  " +
    "AND MatterDataset.matterid = \'100\'   " +
    "ORDER BY d1.id  LIMIT 1 ;") ;
4

2 回答 2

1

我回去重新开始。SQL 语法虽然在 Java 之外工作,但对于 JDBC 驱动程序来说似乎过于复杂。这个清理后的修订似乎有效:

SELECT DISTINCT 
  MatterDataset.id, MatterDataset.sourcefullfilepath, MatterDataset.sourcefilepath,
  MatterDataset.sourcefilename
FROM MatterDataset , DocumentClassification 
  ON DocumentClassification.documentid = MatterDataset.id  
    AND MatterDataset.matterid = DocumentClassification.matterid
LEFT JOIN PrivilegeLog ON MatterDataset.id = PrivilegeLog.documentparentid 
  AND MatterDataset.matterid = PrivilegeLog.matterid
WHERE PrivilegeLog.privilegelogitemid IS NULL  
  AND MatterDataset.matterid = '100' 
  AND (DocumentClassification.classid = 1 OR DocumentClassification.classid = 2) 
  AND DocumentClassification.userid = -99
ORDER BY MatterDataset.id LIMIT 1;

一个很好的教训:仅仅因为你可以在 SQL 中并不意味着你应该。

该语句的作用本质上是在 MatterDataset 表中定位不在 PrivilegeLog 表中的项目。LEFT JOIN 和 IS NULL 语法定位“丢失”的项目。也就是说,我想查找在 MatterDataset 但尚未在 PrivilegeLog 中的项目并返回这些项目。

于 2012-07-14T20:44:31.417 回答
1

多么混乱的 SQL 语句(对不起)!我不知道 SQLite,但为什么不简化为:

SELECT DISTINCT md.id, md.sourcefullfilepath, md.sourcefilepath, md.sourcefilename, 
                dc.classificationid, dc.classid, dc.userid
FROM MatterDataset md
LEFT JOIN DocumentClassification dc
       ON dc.documentid = md.id
      AND (dc.classid = 1 OR dc.classid = 2 )
      AND dc.userid < 0
LEFT JOIN PrivilegeLog pl
       ON md.id = pl.documentparentid 
      AND md.matterid = pl.matterid
WHERE pl.privilegelogitemid IS NULL
  AND md.matterid = \'100\'
ORDER BY md.id LIMIT 1 ;

我不确定您是要 LEFT JOIN 还是 INNER JOIN 到 DocumentClassification(使用 LEFT JOIN 然后在 WHERE 语句中对 classid 和 userid 提出要求 - 在我看来 - 是矛盾的)。如果 DocumentClassification 必须存在,则更改为 INNER JOIN 并将对 classid 和 userid 的引用放入 WHERE 子句中,如果 DocumentClassification 可能存在或可能不存在于您的结果集中,则按照我上面的建议保留查询。

于 2012-07-14T19:33:34.033 回答