SQLite 无法通过 JDBC 和 jOOQ 在 SELECT 中找到现有列

Posted

技术标签:

【中文标题】SQLite 无法通过 JDBC 和 jOOQ 在 SELECT 中找到现有列【英文标题】:SQLite fails to find existing column in SELECT via JDBC and jOOQ 【发布时间】:2014-07-20 19:49:25 【问题描述】:

我在使用 SQLite 和 JDBC 时遇到了一些奇怪的结果(实际上是通过 JOOQ,但是可以通过 JDBC 手动执行查询字符串来重现此问题)。我的数据库由三个表组成,包括多对多和一对多关系。我尝试选择“主”表的所有值,并从关系表中加入所有需要的值:

SELECT location.name, 
       world.world, 
       player.player 
FROM   location 
       JOIN world 
         ON location."world-id" = world."world-id" 
       LEFT OUTER JOIN (location2player 
                         JOIN player 
                           ON location2player."player-id" = player."player-id") 
                    ON location."location-id" = location2player."location-id" 

在 JDBC 中,此查询失败:

java.sql.SQLException: [SQLITE_ERROR] SQL error or missing database (no such column: player.player)

当我在外部 SQLite 编辑器(例如 Firefox 的 SQLite Manager)中执行查询时,它会按预期工作。

我与 sqlite-jdbc-3.7.2 合作,我无法更改。作为参考,JOOQ 查询是:

create.select(LOCATION.NAME,WORLD.WORLD_,PLAYER.PLAYER_)
            .from(LOCATION
                .join(WORLD)
                    .on(LOCATION.WORLD_ID.eq(WORLD.WORLD_ID)
                )
                .leftOuterJoin(LOCATION2PLAYER
                    .join(PLAYER)
                        .onKey()
                    )
                    .on(LOCATION.LOCATION_ID.eq(LOCATION2PLAYER.LOCATION_ID)
                )
            .fetch()

为什么在 JDBC 中这个查询会失败,我应该如何修复它?

【问题讨论】:

JDBC驱动使用的是什么SQLite版本? 【参考方案1】:

虽然我认为您编写了有效的 ANSI SQL,但很可能 SQLite 对您的语句的解释略有不同。但是您实际上并不需要像您那样嵌套连接。试试这个:

SELECT location.name, 
       world.world, 
       player.player 
FROM   location 
       JOIN world 
         ON location."world-id" = world."world-id" 
       LEFT OUTER JOIN location2player 
         ON location."location-id" = location2player."location-id" 
       LEFT OUTER JOIN player 
         ON location2player."player-id" = player."player-id"

【讨论】:

【参考方案2】:

我能够在 sqlite-jdbc-3.7.2 下使用

重新创建您的问题
sql = 
        "SELECT location.name, " +
            "world.world, " + 
            "player.player " + 
        "FROM " +
            "location " + 
            "JOIN world " + 
                "ON location.\"world-id\" = world.\"world-id\" " + 
            "LEFT OUTER JOIN (location2player " + 
                "JOIN " +
                "player " + 
                    "ON location2player.\"player-id\" = player.\"player-id\") " + 
                "ON location.\"location-id\" = location2player.\"location-id\"";

问题似乎是location2playerplayer 表“隐藏”在子连接的括号() 内,并且对于初始列列表和最后的ON 子句不可用。下面的语句通过给子查询一个别名并在这两个地方使用别名来避免这个问题:

sql = 
        "SELECT " +
            "location.name, " +
            "world.world, " + 
            "playerlocation.player " + 
        "FROM " +
            "location " + 
            "JOIN " +
            "world " + 
                "ON location.\"world-id\" = world.\"world-id\" " + 
            "LEFT OUTER JOIN " +
            "( " +
                "SELECT location2player.\"location-id\", player.player " +
                "FROM " +
                    "location2player " + 
                    "JOIN " +
                    "player " + 
                        "ON location2player.\"player-id\" = player.\"player-id\"" +
            ") AS playerlocation " + 
                "ON location.\"location-id\" = playerlocation.\"location-id\"";

【讨论】:

这行得通,谢谢。现在的问题可能是我如何正确地将其移植回 JOOQ 的逻辑 - 可能@lukaseder 有一个想法?使用三个分隔的.as("playerlocation") 子句似乎有点难看。 @thee:所以这真的是 SQLite 限制吗?我会认为原始语句是有效的 ANSI-SQL。我想,只需将您的查询重写为this one @LukasEder 对于它的价值,Mimer SQL-92 Validator 表示原始 SQL 查询是“Transitional SQL-92”。 感谢您的反馈。是的,我是这么认为的。括号中的嵌套连接很少使用,但它应该像非嵌套连接一样工作。不应像涉及派生表时那样更改定义表的范围(如您的解决方法)。

以上是关于SQLite 无法通过 JDBC 和 jOOQ 在 SELECT 中找到现有列的主要内容,如果未能解决你的问题,请参考以下文章

使用JOOQ无法在SQLITE中更新表行

使用jooq上下文将内存sqlite转储到字节[]

在哪里可以获得 jooby 2.10.0 的 jooq 和 jdbc 模块?

使用 JOOQ 更新 SQLITE 中的表行失败

记录真实的 JDBC 连接并生成 Jooq 模拟文件

如何修复:Jooq 代码不会从 sql 脚本为内存 db 中的 sqlite 生成 java 代码