Я хочу создать базу данных SQLite, как на изображениях, как это сделать? Я просто хочу знать, как создать столбец ссылок, чтобы связать базы данных?

#android #sqlite #android-sqlite #sqliteopenhelper

Вопрос:

База данных 1

База данных 2

Я хочу знать, как связать одну базу данных с другой. Например, столбец «Приложения» в таблице » Дни «должен открывать один экземпляр таблицы «Приложения» со следующей датой.

Ответ №1:

Вы можете открыть одну из баз данных, а затем ПОДКЛЮЧИТЬ другую базу данных.

Было бы проще иметь все таблицы в одной базе данных. Наличие единой базы данных со всеми таблицами позволит вам обеспечить целостность ссылок, используя ограничения внешнего ключа (т. Е. Чтобы ссылки действительно ссылались).

Пример присоединения с использованием подкласса SQLiteOpenHelper

Ниже приведен пример подключения второй базы данных, обе базы данных основаны на ваших схемах, с помощью одного помощника базы данных (подкласс SQLiteOpenHelper).

  • Как и в случае с SQLiteOpenHelper для основной базы данных, если вторая база данных не существовала, она будет создана вместе с таблицами.

Хранитель базы данных

 class DatabaseHelper extends SQLiteOpenHelper {

    public static final String DBNAME = "database1";
    public static final int DBVERSION = 1;
    public static final String OTHER_DBNAME = "database2";
    public static final String ATTACH_SCHEMA = "a1";

    public static final String TB_DAYTABLE = "daytable";
    public static final String COL_DATE_DAYTABLE = "date";
    public static final String COL_TOTALTIME_DAYTABLE = "totaltime";
    public static final String COl_UNLOCKCOUNTS_DAYTABLE = "unlockcounts";
    public static final String COL_APPS_DAYTABLE = "apps";

    public static final String TB_APPS = "apps";
    public static final String COl_NAME_APPS = "name";
    public static final String COl_TOTALTIME_APPS = "totaltime";
    public static final String COl_COUNTS_APPS = "counts";
    public static final String COL_TIMELINE_APPS = "timeline";

    public static final String TB_TIMELINE = "timeline";
    public static final String COL_STARTTIME_TIMELINE = "starttime";
    public static final String COL_ENDTIME_TIMELINE = "endtime";
    public static final String COL_TOTALTIME_TIMELINE = "totaltime";


    private static volatile DatabaseHelper instance;
    private SQLiteDatabase db;

    private DatabaseHelper(@Nullable Context context) {
        super(context, DBNAME, null, DBVERSION);
        db = this.getWritableDatabase();
        db.execSQL("ATTACH DATABASE '"   context.getDatabasePath(OTHER_DBNAME)   "' AS "   ATTACH_SCHEMA);
        Cursor csr = db.query(ATTACH_SCHEMA   ".sqlite_master",new String[]{"name"},"name=?",new String[]{TB_TIMELINE},null,null,null);
        if (!csr.moveToFirst()) {
            createAttachedTables(db);
        }
    }

    public static DatabaseHelper getInstance(Context context) {
        if (instance == null) {
            instance = new DatabaseHelper(context);
        }
        return instance;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE IF NOT EXISTS "   TB_DAYTABLE   " ("  
                COL_DATE_DAYTABLE   " TEXT "  
                ","   COL_TOTALTIME_DAYTABLE   " INTEGER "  
                ","   COl_UNLOCKCOUNTS_DAYTABLE   " INTEGER "  
                ","   COL_APPS_DAYTABLE   " INTEGER "  
                ")" );
        db.execSQL("CREATE TABLE IF NOT EXISTS "   TB_APPS   " ("  
                COl_NAME_APPS   " TEXT "  
                ","   COl_TOTALTIME_APPS   " INTEGER "  
                ","   COl_COUNTS_APPS   " INTEGER "  
                ","   COL_TIMELINE_APPS   " TEXT "  
                ")");
    }

    private void createAttachedTables(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE IF NOT EXISTS "   ATTACH_SCHEMA   "."   TB_TIMELINE   "("  
                COL_STARTTIME_TIMELINE   " TEXT "  
                ","   COL_ENDTIME_TIMELINE   " TEXT "  
                ","   COL_TOTALTIME_TIMELINE   " INTEGER "  
                ")");
        db.execSQL("CREATE TABLE IF NOT EXISTS "   ATTACH_SCHEMA   "."   TB_APPS   "("  
                COl_NAME_APPS   " TEXT "  
                ","   COl_TOTALTIME_APPS   " INTEGER "  
                ","   COl_COUNTS_APPS   " INTEGER "  
                ","   COL_TIMELINE_APPS   " TEXT "  
                ")");
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}
 

Помощник был протестирован (подключение 2-й базы данных и создание таблиц), используя следующее в действии (основная активность):-

 public class MainActivity extends AppCompatActivity {

    private DatabaseHelper db;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        db = DatabaseHelper.getInstance(this);
    }
}
 

Результат

Открыв базу данных в инспекторе баз данных Android Studio и извлеките данные из обеих схем (т. Е. из соответствующей таблицы sqlite_master), можно увидеть следующее :-

введите описание изображения здесь

т. е. 2 базы данных подключены, и все 4 таблицы существуют.

использование ПРАГМЫ database_list показывает :-

введите описание изображения здесь

т. е. снова две базы данных


Дополнительный

Учитывая, в чем, по-видимому, заключается ваша проблема, вы хотите хранить данные об использовании приложения. Я считаю, что двух столов было бы достаточно.

То есть таблица ПРИЛОЖЕНИЙ, похоже, дублируется, поэтому не требуется. Во-вторых, количество разблокировок статистики, общее время и т. Д. Можно рассчитать, Просто сохранив время начала и окончания, связанное с соответствующим приложением.

Таким образом, для определения значений можно было бы использовать схему, описанную ниже:-

введите описание изображения здесь

  • где красная линия показывает ссылку с использованием на соответствующее приложение.

Теперь предположим, что таблица приложений содержит:-

введите описание изображения здесь

И таблица использования содержит :-

введите описание изображения здесь

Затем такой запрос, как :-

 SELECT 
    date(usage.startdatetime) AS date, 
    app.appname, count(*) AS unlocks, 
    time(sum(strftime('%s',usage.enddatetime)  -  strftime('%s',usage.startdatetime) ),'unixepoch') AS elapsedtime 
FROM app JOIN usage ON app._id = usage.applink 
GROUP BY date(usage.startdatetime),app._id 
ORDER BY date(usage.startdatetime)  ASC,appname ASC
 

Вернет следующий результат:-

введите описание изображения здесь

  • Таким образом, как вы можете видеть, общее время и количество разблокировок были рассчитаны на лету (т. Е. Нет необходимости хранить значения).

Пример 2 — Решение для 2 таблиц для Android :-

Помощник по базам данных AltDBHelper :-

 class AltDBHelper extends SQLiteOpenHelper {

    public static final String DBNAME = "appusage.db";
    public static final int DBVERSION = 1;

    private static SQLiteDatabase db;
    private static volatile AltDBHelper instance;


    private AltDBHelper(@Nullable Context context) {
        super(context, DBNAME, null, DBVERSION);
        db = this.getWritableDatabase();
    }

    public static AltDBHelper getInstance(Context context) {
        if (instance == null) {
            instance = new AltDBHelper(context);
        }
        return instance;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(AppTable.getCreateSQL());
        db.execSQL(UsageTable.getCreateSQL());
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int i, int i1) {

    }

    /*
        Insert an App into the database
     */
    public long insert(String appName) {
        ContentValues cv = new ContentValues();
        cv.put(AppTable.APPNAME,appName);
        return AltDBHelper.db.insert(AppTable.TBNAME,null,cv);
    }

    /*
        Query to return the Date, App, Number of unlocks and Sum of the Elapsed times (total time)
        by each day by each App
    *   Based upon the query :-
    * SELECT
    *   app.appname,
    *   date(usage.startdatetime),
    *   time(sum(strftime('%s',enddatetime) - strftime('%s',startdatetime)),'unixepoch')
    * FROM usage JOIN app ON app._id = usage.applink
    * GROUP BY date(startdatetime),app._id
    * ORDER BY date(startdatetime),app.appName
    *
     */
    public static final String DATE = "date";
    private static final String DATE_COL_EXPRESSION = "date("   UsageTable.STARTDATETIME_QUALIFIED   ") AS "   DATE;
    
    public static final String APPUNLOCKS = "unlocks";
    private static final String APPUNLOCKS_COL_EXPRESSION = "count(*) AS "   APPUNLOCKS;
    
    public static final String ELAPSEDTIME = "elapsedtime";
    private static final String ELAPSEDTIME_EXPRESSION =
            "time("  
                "sum("  
                        "strftime('%s',"   UsageTable.ENDDATETIME_QUALIFIED   ") "  
                        " - "  
                        " strftime('%s',"   UsageTable.STARTDATETIME_QUALIFIED   ") "  
                    ")"  
                ",'unixepoch'"  
            ")"  
        " AS "   ELAPSEDTIME;

    private static final String APPSTATS_TABLE =
            AppTable.TBNAME   " JOIN "   UsageTable.TBNAME  
                    " ON "  
                    AppTable.APPID_QUALIFIED   " = "  
                    UsageTable.APPLINK_QUALIFIED;


    private static final String DATEPART_GROUPBY = "date("   UsageTable.STARTDATETIME_QUALIFIED   ")";
    private static final String APPPART_GROUPBY = AppTable.APPID_QUALIFIED;
    private static final String GROUPBY = DATEPART_GROUPBY   ","   APPPART_GROUPBY;
    public Cursor getAppDailyStatsAsCursor(Long id) {
        String whereClause = null;
        String[] whereArgs = null;
        if (id != null) {
            whereClause = AppTable.APPID_QUALIFIED   "=?";
            whereArgs = new String[]{String.valueOf(id)};
        }
        return AltDBHelper.db.query(
                APPSTATS_TABLE,
                new String[]{
                        DATE_COL_EXPRESSION,
                        AppTable.APPNAME_QUALIFIED,
                        APPUNLOCKS_COL_EXPRESSION,
                        ELAPSEDTIME_EXPRESSION
                },
                whereClause,
                whereArgs,
                GROUPBY,
                null,
                "date("   UsageTable.STARTDATETIME_QUALIFIED   ") "   " ASC"   ","   AppTable.APPNAME   " ASC"
        );
    }

    /* The App Table name and column definitions */
    public static final class AppTable {
        public static final String TBNAME = "app";
        public static final String APPID = BaseColumns._ID;
        public static final String APPID_QUALIFIED = TBNAME   "."   APPID;
        public static final String APPID_UNIQUE = TBNAME APPID;
        public static final String APPNAME = "appname";
        public static final String APPNAME_QUALIFIED = TBNAME   "."   APPNAME;

        public static String getCreateSQL() {
            return "CREATE TABLE IF NOT EXISTS "   TBNAME   "("  
                    APPID   " INTEGER PRIMARY KEY "  
                    ","   APPNAME   " TEXT UNIQUE "  
                    ")";
        }
    }

    /* The Usage table name and column definitions also method for inserting rows (alternative) */
    public static final class UsageTable {

        public static final String TBNAME = "usage";
        public static final String USAGEID = BaseColumns._ID;
        public static final String USAGEID_QUALIFIED = TBNAME   "."   USAGEID;
        public static final String USAGEID_UNIQUE = TBNAME   USAGEID;
        public static final String APPLINK = "applink";
        public static final String APPLINK_QUALIFIED = TBNAME   "."   APPLINK;
        public static final String STARTDATETIME = "startdatetime";
        public static final String STARTDATETIME_QUALIFIED = TBNAME   "."   STARTDATETIME;
        public static final String ENDDATETIME = "enddatetime";
        public static final String ENDDATETIME_QUALIFIED = TBNAME   "."   ENDDATETIME;

        public static String getCreateSQL() {
            return "CREATE TABLE IF NOT EXISTS "   TBNAME   "("  
                    USAGEID   " INTEGER PRIMARY KEY"  
                    ","   APPLINK   " INTEGER REFERENCES "   AppTable.TBNAME   "("   AppTable.APPID   ") ON DELETE CASCADE ON UPDATE CASCADE"  
                    ","   STARTDATETIME   " TEXT "  
                    ","   ENDDATETIME   " TEXT "  
                    ")";
        }

        public static long insert(long appId, String startDateTime, String endDateTime) {
            ContentValues cv = new ContentValues();
            cv.put(APPLINK,appId);
            cv.put(STARTDATETIME,startDateTime);
            cv.put(ENDDATETIME,endDateTime);
            return AltDBHelper.db.insert(TBNAME,null,cv);
        }
    }
}
 

используя вышесказанное в activit, MainActivity, чтобы получить тот же результат, что и в дополнительном разделе, описанном выше :-

 public class MainActivity extends AppCompatActivity {

    private DatabaseHelper db;
    private AltDBHelper altdb;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        db = DatabaseHelper.getInstance(this); /* The original answer  attaching a second database */

        /* using alternative with just 2 tables */
        altdb = AltDBHelper.getInstance(this); /* get an Instance of the DBHelper */

        /* Add data for App1 along with some usage data */
        long a1 = altdb.insert("App1");
        AltDBHelper.UsageTable.insert(a1,"2021-01-01 15:30:00","2021-01-01 16:00:00");
        AltDBHelper.UsageTable.insert(a1,"2021-01-01 17:21:34","2021-01-01 19:33:12");
        AltDBHelper.UsageTable.insert(a1,"2021-01-02 09:11:27","2021-01-02 09:15:28");
        AltDBHelper.UsageTable.insert(a1,"2021-01-03 00:00:00","2021-01-03 05:00:59");

        /* Likewise for App2 */
        long a2 = altdb.insert("App2");
        AltDBHelper.UsageTable.insert(a2,"2021-01-01 13:04:27","2021-01-01 13:06:07");
        AltDBHelper.UsageTable.insert(a2,"2021-01-03 12:51:51","2021-01-03 12:55:55");
        AltDBHelper.UsageTable.insert(a2,"2021-01-02 03:33:30","2021-01-02 03:33:35");
        AltDBHelper.UsageTable.insert(a2,"2021-01-02 01:01:01","2021-01-02 01:03:04");
        AltDBHelper.UsageTable.insert(a2,"2021-01-01 14:25:36","2021-01-01 15:26:37");

        /* Add just App3 with no usage data */
        long a3 = altdb.insert("App3");

        /* Get the Daily App Usage */
        Cursor csr = altdb.getAppDailyStatsAsCursor(null);
        DatabaseUtils.dumpCursor(csr); /* Dump the Cursor (just to show what the Cursor contains) */
        csr.close(); /* done with the Cursor so close it */
    }
}
 
  • Как видно, исходный код, показывающий, как подключить базу данных, был оставлен.

Когда вышеописанное запускается в первый раз (не предназначено для повторного запуска, так как это просто демонстрация), дамп курсора выглядит следующим образом :-

 2021-05-30 18:29:23.739 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@9ba4107
2021-05-30 18:29:23.742 I/System.out: 0 {
2021-05-30 18:29:23.742 I/System.out:    date=2021-01-01
2021-05-30 18:29:23.743 I/System.out:    appname=App1
2021-05-30 18:29:23.743 I/System.out:    unlocks=2
2021-05-30 18:29:23.743 I/System.out:    elapsedtime=02:41:38
2021-05-30 18:29:23.744 I/System.out: }
2021-05-30 18:29:23.744 I/System.out: 1 {
2021-05-30 18:29:23.744 I/System.out:    date=2021-01-01
2021-05-30 18:29:23.744 I/System.out:    appname=App2
2021-05-30 18:29:23.745 I/System.out:    unlocks=2
2021-05-30 18:29:23.745 I/System.out:    elapsedtime=01:02:41
2021-05-30 18:29:23.745 I/System.out: }
2021-05-30 18:29:23.746 I/System.out: 2 {
2021-05-30 18:29:23.746 I/System.out:    date=2021-01-02
2021-05-30 18:29:23.746 I/System.out:    appname=App1
2021-05-30 18:29:23.747 I/System.out:    unlocks=1
2021-05-30 18:29:23.747 I/System.out:    elapsedtime=00:04:01
2021-05-30 18:29:23.747 I/System.out: }
2021-05-30 18:29:23.747 I/System.out: 3 {
2021-05-30 18:29:23.748 I/System.out:    date=2021-01-02
2021-05-30 18:29:23.748 I/System.out:    appname=App2
2021-05-30 18:29:23.749 I/System.out:    unlocks=2
2021-05-30 18:29:23.749 I/System.out:    elapsedtime=00:02:08
2021-05-30 18:29:23.749 I/System.out: }
2021-05-30 18:29:23.749 I/System.out: 4 {
2021-05-30 18:29:23.750 I/System.out:    date=2021-01-03
2021-05-30 18:29:23.750 I/System.out:    appname=App1
2021-05-30 18:29:23.750 I/System.out:    unlocks=1
2021-05-30 18:29:23.750 I/System.out:    elapsedtime=05:00:59
2021-05-30 18:29:23.751 I/System.out: }
2021-05-30 18:29:23.751 I/System.out: 5 {
2021-05-30 18:29:23.751 I/System.out:    date=2021-01-03
2021-05-30 18:29:23.751 I/System.out:    appname=App2
2021-05-30 18:29:23.751 I/System.out:    unlocks=1
2021-05-30 18:29:23.752 I/System.out:    elapsedtime=00:04:04
2021-05-30 18:29:23.752 I/System.out: }
2021-05-30 18:29:23.752 I/System.out: <<<<<
 

Комментарии:

1. Это лучший ответ, который я когда-либо видел в stack overflow. Спасибо за подробный ответ, это сработало, но мне потребовалось некоторое время, чтобы понять весь код.