SQLite - 跨数据库查询不起作用

Posted

技术标签:

【中文标题】SQLite - 跨数据库查询不起作用【英文标题】:SQLite - Cross Database Query not working 【发布时间】:2018-04-15 20:40:41 【问题描述】:

我想在 android 的 SQLite 中执行跨数据库查询。我在两个不同的数据库中有两个表。

attach database 'data/data/com.app/databases/db1' as db1; 
attach database 'data/data/com.app/databases/db2' as db2; 
SELECT db1.tbl1.* FROM db1.tbl1 JOIN db2.tbl2 ON db1.tbl1.primaryKey = db2.tbl2.primaryKey 
WHERE db1.tbl1.columnX = ?  AND db2.tbl2.columnY  = ? 

通过使用 Android rawQuery 方法调用此查询,例如:

Cursor cursor = sqLiteDatabase.rawQuery(selectQuery, new String[]"1","xyz");

我收到此错误:

SQLiteException: bind or column index out of range: handle 0xa6259ec8

我检查了查询的语法,它是正确的。 Android中不能执行跨库查询吗?

【问题讨论】:

查看***.com/a/4499816/3364266 @SamirBhatt 是的,打开多个数据库工作正常,但查询数据不起作用。 相同的 db 文件:将数据库 'data/data/com.app/databases/db1' 附加为 db1;将数据库 'data/data/com.app/databases/db1' 附加为 db2; @ViktorYakunin 抱歉,这是我的错字。已更正 【参考方案1】:

我检查了查询的语法,它是正确的。是不是不可能 在Android中执行跨数据库查询?

是的,正如所包含的示例所展示的那样。

我认为您的问题是您似乎使用了不正确的rawQuery 方法/签名。

而不是:-

        Cursor cursor = sqLiteDatabase.rawQuery(selectQuery, "1","xyz");

我相信你应该使用:-

        Cursor cursor = sqLiteDatabase.rawQuery(selectQuery, new String[]"1","xyz");

前者仅提供 1 个绑定项,而不是两个预期的绑定项(尽管您使用的甚至不是 rawQuery 的有效签名

但是,我确实怀疑,通过测试您在查询方面还有其他问题。这是一个基于您的原始帖子的工作示例(即附加的数据库实际上是相同的数据库,但这在原则上应该无关紧要):-

public class MainActivity extends AppCompatActivity 

    public static final String DBNAME1 = "db1";
    public static final String DBNAME2 = "db2";
    public static final String DBNAME3 = "db3";
    public static final String ID_COLUMN = "_id";
    public static final String TABLENAME_BASE = "_table_main";
    public static final String NAMECOLUMN_BASE = "_name";
    public static final String DB2_COL_NAME = DBNAME2 + NAMECOLUMN_BASE;
    public static final String EXTENDED_DB2TABLENAME = DBNAME2 + "." + DBNAME2 + TABLENAME_BASE;
    public static final String EXTENDED_DB3TABLENAME = DBNAME3 + "." + DBNAME2 + TABLENAME_BASE;
    public static final String DB2_FULL_IDCOL = EXTENDED_DB2TABLENAME + "." + ID_COLUMN;
    public static final String DB2_FULL_NAMECOL = EXTENDED_DB2TABLENAME + "." + DBNAME2 + NAMECOLUMN_BASE;
    public static final String DB3_FULL_IDCOL = EXTENDED_DB3TABLENAME + "." + ID_COLUMN;
    public static final String DB3_FULL_NAMECOL = EXTENDED_DB3TABLENAME + "." + DBNAME2 + NAMECOLUMN_BASE;

    private static final String[] DB1NAMES = new String[] "Fred","Bert","Harry","Tom","Dick";
    private static final String[] DB2NAMES = new String[] "Alan","George","Robert","Colin","Ian","John";

    String mDB1Path, mDB2path;
    SQLiteDatabase mMaster;


    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mDB1Path = createDatbase(DBNAME1);
        mDB2path = createDatbase(DBNAME2);

        /* Just to add some data for 1st run
        for (String s: DB2NAMES) 
            insertRow(DBNAME1,s);
        
        for (String s: DB1NAMES) 
            insertRow(DBNAME2,s);
        
        */

       // Open the main database and attach databases
        mMaster = this.openOrCreateDatabase(mDB1Path, Context.MODE_PRIVATE,null);
        String attachsql = "ATTACH DATABASE '" + mDB2path + "' AS " + DBNAME2;
        String attachsql2 = "ATTACH DATABASE '" + mDB2path + "' AS " +  DBNAME3;
        mMaster.execSQL(attachsql);
        mMaster.execSQL(attachsql2);

        // Prepare first query between all 3 DB's
        String sqlstr = "SELECT " +
                DBNAME1 + TABLENAME_BASE + ".*, " +
                DBNAME2 + "." + DBNAME2 + TABLENAME_BASE + "." + DB2_COL_NAME +
                ", " + DBNAME3 + "." + DBNAME2 + TABLENAME_BASE + "." + DB2_COL_NAME +
                " FROM " + DBNAME1 + TABLENAME_BASE +
                " JOIN " + DBNAME2 + "." + DBNAME2 + TABLENAME_BASE +
                " ON " + DBNAME1 + TABLENAME_BASE + "." + ID_COLUMN +
                " =  " + DBNAME2 + "." + DBNAME2 + TABLENAME_BASE + "." + ID_COLUMN +
                " JOIN " + DBNAME3 + "." + DBNAME2 + TABLENAME_BASE +
                " ON " + DBNAME1 + TABLENAME_BASE + "." + ID_COLUMN +
                " =  " + DBNAME3 + "." + DBNAME2 + TABLENAME_BASE + "." + ID_COLUMN;

        // Write query string to log
        Log.d("SELECTSQL_1",sqlstr);
        // Perform the query an write resultant data to the log
        Cursor csr = mMaster.rawQuery(sqlstr,null);
        while (csr.moveToNext()) 
            String logdata = "Row = " + csr.getPosition();
            for (int i=0; i < csr.getColumnCount(); i++) 
                logdata = logdata + " Column = " + csr.getColumnName(i) +
                        " Value = " + csr.getString(i);
            
            Log.d("CSRINFO",logdata);
        

        // Arguments for 2nd query
        String arg1 = "12";
        String arg2 = "Fred";

        // SQL for 2nd query including WHERE clause
        String sqlstr2 = " SELECT " +
                DB2_FULL_IDCOL + ", " +
                DB2_FULL_NAMECOL + ", " +
                DB3_FULL_IDCOL + ", " +
                DB3_FULL_NAMECOL +
                " FROM " + DBNAME2 + TABLENAME_BASE +
                " JOIN " + DBNAME3 + "." + DBNAME2 + TABLENAME_BASE +
                " ON   " + DBNAME2 + "." + DBNAME2 + TABLENAME_BASE + "." + ID_COLUMN +
                " =    " + DB3_FULL_IDCOL +
                " WHERE " +
                DB3_FULL_IDCOL + "=? AND " +
                DB3_FULL_NAMECOL + "=?";

        // Log the query string
        Log.d("SELECTSQL_2",sqlstr2);
        // Perform 2nd query and log cursor result 
        Cursor csr2 = mMaster.rawQuery(sqlstr2,new String[]arg1,arg2);
        while (csr2.moveToNext()) 
            String logdata = "Row = " + csr2.getPosition();
            for (int i=0; i < csr2.getColumnCount(); i++) 
                logdata = logdata + " Column = " + csr2.getColumnName(i) +
                        " Value = " + csr2.getString(i);
            
            Log.d("CSRINFO",logdata);
        
    

    // Used to create the two actual databases
    private String createDatbase(String dbqualifier) 
        SQLiteDatabase db = this.openOrCreateDatabase(dbqualifier,Context.MODE_PRIVATE,null);
        String tblcrtstr = "CREATE TABLE IF NOT EXISTS " +
                dbqualifier + TABLENAME_BASE +
                "(" +
                ID_COLUMN + " INTEGER PRIMARY KEY, " +
                dbqualifier + NAMECOLUMN_BASE  + " TEXT" +
                ")";
        db.execSQL(tblcrtstr);
        String rv = db.getPath();
        db.close();
        return rv;
    

    // Insert a row to the respective database
    private void insertRow(String dbqualifier, String name) 
        SQLiteDatabase db = this.openOrCreateDatabase(dbqualifier,MODE_PRIVATE,null);
        ContentValues cv = new ContentValues();
        cv.put(dbqualifier + NAMECOLUMN_BASE, name);
        db.insert(dbqualifier + TABLENAME_BASE,null,cv);
        db.close();
    

我相信您主要对第二个查询感兴趣:-

SELECT db2.db2_table_main._id, db2.db2_table_main.db2_name, db3.db2_table_main._id, db3.db2_table_main.db2_name FROM db2_table_main JOIN db3.db2_table_main ON   db2.db2_table_main._id =    db3.db2_table_main._id WHERE db3.db2_table_main._id=? AND db3.db2_table_main.db2_name=?

请注意,上面的查询是基于原始帖子,其中两次附加了相同的数据库。

运行上述代码(经过多次运行,包括注释掉的行插入代码)产生了以下结果:-

来自/对于第一个查询:-

11-05 07:37:52.764 2726-2726/? D/SELECTSQL_1: SELECT db1_table_main.*, db2.db2_table_main.db2_name, db3.db2_table_main.db2_name FROM db1_table_main JOIN db2.db2_table_main ON db1_table_main._id =  db2.db2_table_main._id JOIN db3.db2_table_main ON db1_table_main._id =  db3.db2_table_main._id
11-05 07:37:52.764 2726-2726/? D/CSRINFO: Row = 0 Column = _id Value = 1 Column = db1_name Value = Fred Column = db2_name Value = Alan Column = db2_name Value = Alan
11-05 07:37:52.764 2726-2726/? D/CSRINFO: Row = 1 Column = _id Value = 2 Column = db1_name Value = Bert Column = db2_name Value = George Column = db2_name Value = George
11-05 07:37:52.764 2726-2726/? D/CSRINFO: Row = 2 Column = _id Value = 3 Column = db1_name Value = Harry Column = db2_name Value = Robert Column = db2_name Value = Robert
11-05 07:37:52.764 2726-2726/? D/CSRINFO: Row = 3 Column = _id Value = 4 Column = db1_name Value = Tom Column = db2_name Value = Colin Column = db2_name Value = Colin
11-05 07:37:52.764 2726-2726/? D/CSRINFO: Row = 4 Column = _id Value = 5 Column = db1_name Value = Dick Column = db2_name Value = Ian Column = db2_name Value = Ian
11-05 07:37:52.764 2726-2726/? D/CSRINFO: Row = 5 Column = _id Value = 6 Column = db1_name Value = Alan Column = db2_name Value = John Column = db2_name Value = John
11-05 07:37:52.764 2726-2726/? D/CSRINFO: Row = 6 Column = _id Value = 7 Column = db1_name Value = George Column = db2_name Value = Fred Column = db2_name Value = Fred
11-05 07:37:52.764 2726-2726/? D/CSRINFO: Row = 7 Column = _id Value = 8 Column = db1_name Value = Robert Column = db2_name Value = Bert Column = db2_name Value = Bert
11-05 07:37:52.764 2726-2726/? D/CSRINFO: Row = 8 Column = _id Value = 9 Column = db1_name Value = Colin Column = db2_name Value = Harry Column = db2_name Value = Harry
11-05 07:37:52.764 2726-2726/? D/CSRINFO: Row = 9 Column = _id Value = 10 Column = db1_name Value = Ian Column = db2_name Value = Tom Column = db2_name Value = Tom
11-05 07:37:52.764 2726-2726/? D/CSRINFO: Row = 10 Column = _id Value = 11 Column = db1_name Value = John Column = db2_name Value = Dick Column = db2_name Value = Dick
11-05 07:37:52.764 2726-2726/? D/CSRINFO: Row = 11 Column = _id Value = 12 Column = db1_name Value = Alan Column = db2_name Value = Fred Column = db2_name Value = Fred
11-05 07:37:52.765 2726-2726/? D/CSRINFO: Row = 12 Column = _id Value = 13 Column = db1_name Value = George Column = db2_name Value = Bert Column = db2_name Value = Bert
11-05 07:37:52.765 2726-2726/? D/CSRINFO: Row = 13 Column = _id Value = 14 Column = db1_name Value = Robert Column = db2_name Value = Harry Column = db2_name Value = Harry
11-05 07:37:52.765 2726-2726/? D/CSRINFO: Row = 14 Column = _id Value = 15 Column = db1_name Value = Colin Column = db2_name Value = Tom Column = db2_name Value = Tom
11-05 07:37:52.765 2726-2726/? D/CSRINFO: Row = 15 Column = _id Value = 16 Column = db1_name Value = Ian Column = db2_name Value = Dick Column = db2_name Value = Dick

从带有 WHERE 子句的第二个查询:-

11-05 07:37:52.765 2726-2726/? D/SELECTSQL_2:  SELECT db2.db2_table_main._id, db2.db2_table_main.db2_name, db3.db2_table_main._id, db3.db2_table_main.db2_name FROM db2_table_main JOIN db3.db2_table_main ON   db2.db2_table_main._id =    db3.db2_table_main._id WHERE db3.db2_table_main._id=? AND db3.db2_table_main.db2_name=?
11-05 07:37:52.765 2726-2726/? D/CSRINFO: Row = 0 Column = _id Value = 12 Column = db2_name Value = Fred Column = _id Value = 12 Column = db2_name Value = Fred

即它只选择了 16 行中的一行,即 _id 列中有 12Fred 的一行> 在第二个附加 (db3) 数据库的 名称 列中。

【讨论】:

这是一个错字。你能帮忙吗?

以上是关于SQLite - 跨数据库查询不起作用的主要内容,如果未能解决你的问题,请参考以下文章

具有多态连接的 Laravel 查询生成器在 SQLite 上不起作用

Sqlite FTS5 标点符号在选择查询中不起作用

在 Sqlite 中,LIKE 函数不起作用或不返回任何内容

查询从 sqlite 数据库中检索两个时间之间的数据?

需要调整我的 FTS4 SQLite 查询

SQLite INSERT SELECT 查询结果到现有表中?