来自已存在的多个数据库的Sqlite查询

时间:2017-12-07 23:55:37

标签: android database sqlite

我很难将以下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已连接在命令行中工作,那么是否应该在代码中使用? 我在代码中遗漏了什么吗?

1 个答案:

答案 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();
    }
}

尝试重新创建相同的错误: -

1 - 尝试使用具有不存在文件的路径打开: -

将代码更改为: -

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

2 - 跳过打开并尝试附加不存在的文件: -

e.g。 ATTACH DATABASE '/data/data/mjt.attachdatabases/db2blah' AS db2

ATTACH可以正常工作但由于找不到表而失败(即数据库已创建,因为attach似乎使用openOrCreate,但没有用户定义的表)。

3 - 尝试附加不是数据库文件的数据库,在这种情况下,pdf文件重命名为db2blah。

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

以上所有内容似乎都不符合错误。因此,问题可能是数据库文件没有适当的权限,另一种可能性是文件可能正在使用中。