我想在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中执行跨数据库查询?
答案 0 :(得分:0)
我检查了查询的语法,这是正确的。是不可能的 在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 列中 12 的一行和 Fred 在第二个附加(db3)数据库的名称列中。