我想创建一个像图像中那样的 SQLite 数据库,我该怎么做?我只想知道如何创建 link 列以便 link 数据库?
I want to create a SQLite database like in the images how do I do it? I just want to know how to I create the link column so as to link databases?
Database 1
Database 2
我想知道如何 link 一个数据库到另一个数据库。
例如,第 table 天的应用程序列应打开具有以下日期的应用程序 table 的一个实例。
您可以打开其中一个数据库,然后ATTACH另一个数据库。
将所有 table 放在一个数据库中会更简单。拥有一个包含所有 table 的数据库将允许您通过使用外键约束来强制执行参照完整性(即 link 实际上是 link)。
利用 SQLiteOpenHelper 子类进行附加的示例
以下是通过单一数据库助手(SQliteOpenHelper 的子类)附加第二个数据库的示例,这两个数据库都基于您的模式。
- 就像对主数据库使用 SQLiteOpenHelper 所做的那样,如果第二个数据库不存在,它将与 tables 一起创建。
数据库助手
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) {
}
}
Helper 已经过测试(附加第二个数据库并创建 tables)在 Activity(MainActivity)中使用以下内容:-
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 table)然后可以看到以下内容:-
即附加了 2 个数据库,所有 4 个 table 都存在。
使用 database_list PRAGMA 显示:-
即又是两个数据库
额外
考虑到您的问题似乎是您想要存储应用程序使用数据。我相信两个 table 就足够了。
那是 APPS table 似乎是重复的,因此不需要。
其次,统计解锁次数、总时间等可以通过将开始和结束时间存储 linked 到相应的应用程序来计算。
因此,可以使用如下模式来确定值:-
- 其中红线显示 link 从 Usage 到相应 App.
现在假设应用 table 包含:-
而用法 table 包含:-
然后查询如:-
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
请问return如下结果:-
- 如您所见,总时间和解锁次数是即时计算的(即无需存储这些值)。
示例 2 - Android 的第 2 table 解决方案:-
数据库助手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);
}
}
}
在活动中使用上述内容,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 */
}
}
- 可以看出,显示如何附加数据库的原始代码已被保留。
当上面是第一次运行时(不是为了re运行而设计的,因为它只是一个演示),Cursor的转储如下:-
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: <<<<<
Database 1
Database 2
我想知道如何 link 一个数据库到另一个数据库。 例如,第 table 天的应用程序列应打开具有以下日期的应用程序 table 的一个实例。
您可以打开其中一个数据库,然后ATTACH另一个数据库。
将所有 table 放在一个数据库中会更简单。拥有一个包含所有 table 的数据库将允许您通过使用外键约束来强制执行参照完整性(即 link 实际上是 link)。
利用 SQLiteOpenHelper 子类进行附加的示例
以下是通过单一数据库助手(SQliteOpenHelper 的子类)附加第二个数据库的示例,这两个数据库都基于您的模式。
- 就像对主数据库使用 SQLiteOpenHelper 所做的那样,如果第二个数据库不存在,它将与 tables 一起创建。
数据库助手
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) {
}
}
Helper 已经过测试(附加第二个数据库并创建 tables)在 Activity(MainActivity)中使用以下内容:-
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 table)然后可以看到以下内容:-
即附加了 2 个数据库,所有 4 个 table 都存在。
使用 database_list PRAGMA 显示:-
即又是两个数据库
额外
考虑到您的问题似乎是您想要存储应用程序使用数据。我相信两个 table 就足够了。
那是 APPS table 似乎是重复的,因此不需要。 其次,统计解锁次数、总时间等可以通过将开始和结束时间存储 linked 到相应的应用程序来计算。
因此,可以使用如下模式来确定值:-
- 其中红线显示 link 从 Usage 到相应 App.
现在假设应用 table 包含:-
而用法 table 包含:-
然后查询如:-
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
请问return如下结果:-
- 如您所见,总时间和解锁次数是即时计算的(即无需存储这些值)。
示例 2 - Android 的第 2 table 解决方案:-
数据库助手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);
}
}
}
在活动中使用上述内容,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 */
}
}
- 可以看出,显示如何附加数据库的原始代码已被保留。
当上面是第一次运行时(不是为了re运行而设计的,因为它只是一个演示),Cursor的转储如下:-
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: <<<<<