Android SQLite语法错误,使用RANK创建视图

问题描述

我正在尝试使用RANK()窗口函数sqlite中创建视图。当我执行以下代码时:

val txt = "CREATE VIEW VW_CAPITULOS_ORDER AS\n" +
          "    SELECT id_libro,capitulo,\n" +
          "            RANK() OVER (\n" +
          "                ORDER BY id_libro,CAST(SUBSTR(capitulo,1,INSTR(capitulo||' ',' ')) AS INTEGER)\n" +
          "                ) ranking\n" +
          "        FROM tbl_capitulos;\n"

db.execsql(txt)

在运行时,我收到以下异常:

*E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.systango.bibliacatolica,PID: 20837
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.systango.bibliacatolica/com.systango.bibliacatolica.MainActivity}: android.database.sqlite.sqliteException: near "(": Syntax error (sqlite code 1 sqlITE_ERROR):,while compiling: CREATE VIEW VW_CAPITULOS_ORDER AS
        SELECT id_libro,RANK() OVER (
                    ORDER BY id_libro,' ')) AS INTEGER)
                    ) ranking
            FROM tbl_capitulos;,(OS error - 11:Try again)
        at android.app.ActivityThread.performlaunchActivity(ActivityThread.java:3897)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4076)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:91)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:149)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:103)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2473)
        at android.os.Handler.dispatchMessage(Handler.java:110)
        at android.os.Looper.loop(Looper.java:219)
        at android.app.ActivityThread.main(ActivityThread.java:8349)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)
     Caused by: android.database.sqlite.sqliteException: near "(": Syntax error (sqlite code 1 sqlITE_ERROR):,(OS error - 11:Try again)
        at android.database.sqlite.sqliteConnection.nativePrepareStatement(Native Method)
        at android.database.sqlite.sqliteConnection.acquirePreparedStatement(sqliteConnection.java:1030)
        at android.database.sqlite.sqliteConnection.prepare(sqliteConnection.java:637)
        at android.database.sqlite.sqliteSession.prepare(sqliteSession.java:610)
        at android.database.sqlite.sqliteProgram.<init>(sqliteProgram.java:66)
        at android.database.sqlite.sqliteStatement.<init>(sqliteStatement.java:33)
        at android.database.sqlite.sqliteDatabase.executesql(sqliteDatabase.java:1899)
        at android.database.sqlite.sqliteDatabase.execsql(sqliteDatabase.java:1817)*

我怀疑这是Android中存在的sqlite版本(在华为P40 Lite上检查为3.22版本)或类似问题。 sqlite文档说,窗口功能出现在3.25版(https://sqlite.org/windowfunctions.html)中。该脚本在DB browser for sqlite应用中执行没有问题。是否存在使用手机随附版本的sqlite新版本的方法

解决方法

您的应用无法更改手机的SQLite版本。
解决方法是,可以使用相关子查询来模仿窗口函数RANK()的功能:

CREATE VIEW VW_CAPITULOS_ORDER AS
SELECT c.id_libro,c.capitulo,(
         SELECT COUNT(*) FROM tbl_capitulos 
         WHERE id_libro < c.id_libro 
            OR (id_libro = c.id_libro AND (capitulo + 0) < (c.capitulo + 0))
       ) + 1 ranking
FROM tbl_capitulos c;

请注意,您无需将capitulo的子字符串带到第一个' '即可将其转换为整数。
您可以通过添加0来进行隐式转换。