我很难将以下sqlite查询转换为Android源代码。
我有两个数据库: - db1:程序表 - db2:事件表
以下是查询:
sqlite3 db1.db
将数据库'/data/data/com.stack.test/db2.db'附加为db2;
从main.program中选择a.show_id a.show_id上的b.program_id = a.program_id组中的内连接db2.event b;
上面的查询工作正常,我得到了所需的输出。
我很难将此查询转换为android java代码。 数据库已经创建。我只是想打开它们并查询。
这是我的代码:
SQLiteDatabase mDb = getDatabaseOpener().getWritableDatabase(); <-- this returns db1
String attachDb = "attach database '" + "/data/data/com.stack.test/db2.db" + "' as db2";
mDb.execSQL(attachDb);
String tables = "main.program INNER JOIN db2.event ON db2.event.program_id=main.program.program_id";
String groupBy = "main.program.show_id";
String rawShowsQuery = SQLiteQueryBuilder.buildQueryString(false, tables,
SHOWS_PROJECTION, null, groupBy, null, null, null);
try (Cursor cursor = mDb.rawQuery(rawShowsQuery, null)) {
if (cursor == null) {
return Collections.emptyList();
} else {
while (cursor.moveToNext()) {
// do something
}
}
}
我收到以下错误:
E / SQLiteDatabase(9952):无法打开数据库'/data/data/com.stack.test/db2.db'。 E / SQLiteDatabase(9952):android.database.sqlite.SQLiteCantOpenDatabaseException:未知错误(代码14):无法打开数据库
如果将db2连接到db1已连接在命令行中工作,那么是否应该在代码中使用? 我在代码中遗漏了什么吗?
答案 0 :(得分:0)
这是一个完全有效的例子(尽管附带3个用于演示目的,并且由于列名重复可能过于复杂): -
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);
// Check that can be added for those who are too arrogant to
// even consider they may have the incorrect path name coded
// when hard coding the path rather than obtaining it via code.
Log.d("DBPATHS","Path for " + DBNAME1 + " is " + mDB1Path);
Log.d("DBPATHS","Path for " + DBNAME2 + " is " + mDBPath2);
/* Only uncomment for first run to populate database tables
for (String s: DB2NAMES) {
insertRow(DBNAME1,s);
}
for (String s: DB1NAMES) {
insertRow(DBNAME2,s);
}
*/
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);
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;
Log.d("SELECTSQL_1",sqlstr);
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);
}
String arg1 = "12";
String arg2 = "Fred";
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 " +
DB2_FULL_IDCOL + "=? AND " +
DB3_FULL_NAMECOL + "=?";
Log.d("SELECTSQL_2",sqlstr2);
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);
}
}
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;
}
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();
}
}
你的问题是它无法打开数据库db2,可能是因为路径不正确。以上根据数据库名称获取路径。
上面的示例输出(注意第二个查询有目的地导致空光标,它是一个处理名为_id的多个列的示例): -
12-07 19:32:26.764 2913-2913/mjt.attachdatabases 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
12-07 19:32:26.764 2913-2913/mjt.attachdatabases D/CSRINFO: Row = 0 Column = _id Value = 1 Column = db1_name Value = Alan Column = db2_name Value = Fred Column = db2_name Value = Fred
12-07 19:32:26.764 2913-2913/mjt.attachdatabases D/CSRINFO: Row = 1 Column = _id Value = 2 Column = db1_name Value = George Column = db2_name Value = Bert Column = db2_name Value = Bert
12-07 19:32:26.764 2913-2913/mjt.attachdatabases D/CSRINFO: Row = 2 Column = _id Value = 3 Column = db1_name Value = Robert Column = db2_name Value = Harry Column = db2_name Value = Harry
12-07 19:32:26.764 2913-2913/mjt.attachdatabases D/CSRINFO: Row = 3 Column = _id Value = 4 Column = db1_name Value = Colin Column = db2_name Value = Tom Column = db2_name Value = Tom
12-07 19:32:26.764 2913-2913/mjt.attachdatabases D/CSRINFO: Row = 4 Column = _id Value = 5 Column = db1_name Value = Ian Column = db2_name Value = Dick Column = db2_name Value = Dick
12-07 19:32:26.764 2913-2913/mjt.attachdatabases 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 db2.db2_table_main._id=? AND db3.db2_table_main.db2_name=?
使用默认权限在3个设备API 16,23和24上进行了测试。 现在使用来自不同目录的数据库。
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"};
private static final String altbasepath = "/data/data/mjt.attachdatabases/";
String mDB1Path, mDB2path, mDBA1Path, mDBA2Path;
SQLiteDatabase mMaster, mAltMaster;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDB1Path = createDatbase(DBNAME1);
mDB2path = createDatbase(DBNAME2);
mDBA1Path = createDatabase(DBNAME1,altbasepath);
mDBA2Path = createDatabase(DBNAME2,altbasepath);
// Only uncomment for first run to populate database tables
for (String s: DB2NAMES) {
insertRow(DBNAME1,s);
insertAltRow(DBNAME2,s);
}
for (String s: DB1NAMES) {
insertRow(DBNAME2,s);
insertAltRow(DBNAME1,s);
}
Log.d("DBPATHS", "DB1 Path=" + mDB1Path + " - DSB2 path=" + mDB2path);
Log.d("DBPATHS", "ADB1 Path=" + mDBA1Path + " - DADB2 path=" + mDBA2Path);
mMaster = this.openOrCreateDatabase(mDB1Path, Context.MODE_PRIVATE,null);
mAltMaster = this.openOrCreateDatabase(mDBA1Path,Context.MODE_PRIVATE,null);
/*
String altattachsql = "ATTACH DATABASE '" + mDBA2Path + "' AS " + DBNAME2;
String attachsql = "ATTACH DATABASE '" + mDB2path + "' AS " + DBNAME2;
String aaltttachsql2 = "ATTACH DATABASE '" + mDB2path + "' AS " + DBNAME3;
String attachsql2 = "ATTACH DATABASE '" + mDB2path + "' AS " + DBNAME3;
mMaster.execSQL(attachsql);
mMaster.execSQL(attachsql2);
mAltMaster.execSQL(altattachsql);
mAltMaster.execSQL(aaltttachsql2);
*/
String mdattachsql = "ATTACH DATABASE '" + mDBA2Path + "' AS " + DBNAME2;
String mdattachsql2 = "ATTACH DATABASE '" + mDBA2Path + "' AS " + DBNAME3;
mMaster.execSQL(mdattachsql);
mMaster.execSQL(mdattachsql2);
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;
Log.d("SELECTSQL_1",sqlstr);
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);
}
/*
Log.d("SELECTSQL_ALT",sqlstr);
Cursor acsr = mAltMaster.rawQuery(sqlstr,null);
while (acsr.moveToNext()) {
String logdata = "Row = " + acsr.getPosition();
for (int i=0; i < acsr.getColumnCount(); i++) {
logdata = logdata + " Column = " + acsr.getColumnName(i) +
" Value = " + acsr.getString(i);
}
Log.d("CSRINFO",logdata);
}
*/
String arg1 = "12";
String arg2 = "Fred";
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 " +
DB2_FULL_IDCOL + "=? AND " +
DB3_FULL_NAMECOL + "=?";
Log.d("SELECTSQL_2",sqlstr2);
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);
}
}
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;
}
private String createDatabase(String dbqualifier, String altpath) {
SQLiteDatabase db = this.openOrCreateDatabase(altpath + "/" + 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;
}
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();
}
private void insertAltRow(String dbqualifier, String name) {
SQLiteDatabase db = this.openOrCreateDatabase(altbasepath + "/" + dbqualifier, MODE_PRIVATE,null);
ContentValues cv = new ContentValues();
cv.put(dbqualifier + NAMECOLUMN_BASE, name);
db.insert(dbqualifier + TABLENAME_BASE, null, cv);
db.close();
}
}
将代码更改为: -
mAltMaster = this.openOrCreateDatabase(mDBA1Path+"x",Context.MODE_PRIVATE,null);
未能尝试打开: -
12-08 06:03:31.294 1482-1482/? E/SQLiteLog: (14) cannot open file at line 30174 of [00bb9c9ce4]
12-08 06:03:31.294 1482-1482/? E/SQLiteLog: (14) os_unix.c:30174: (21) open(/data/data/mjt.attachdatabases/db1x) -
12-08 06:03:31.294 1482-1482/? E/SQLiteDatabase: Failed to open database '/data/data/mjt.attachdatabases/db1x'.
android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
e.g。 ATTACH DATABASE '/data/data/mjt.attachdatabases/db2blah' AS db2
ATTACH可以正常工作但由于找不到表而失败(即数据库已创建,因为attach似乎使用openOrCreate,但没有用户定义的表)。
ATTACH失败了: -
E/SQLiteLog: (26) statement aborts at 5: [ATTACH DATABASE '/data/data/mjt.attachdatabases/db2blah' AS db2] file is encrypted or is not a database
以上所有内容似乎都不符合错误。因此,问题可能是数据库文件没有适当的权限,另一种可能性是文件可能正在使用中。