我有三个表:log
,activity
和加入表(many2many)log_activity
(log_id
和activity_id
+其他信息数据作为列)
我想从log
和log_activity
删除。
我希望保留特定用户的所有日志,并且只保留其他用户的100行。
这意味着我想要删除与WHERE log.user_id != 1
匹配的所有行,但最后100行(ORDER BY log.timestamp DESC
)。
我还想从连接表log_activity
中删除与删除的日志相关的所有条目。 <{1}}表格应该不。
我认为activity
在这种情况下没有帮助..
有人能够提出高效的解决方案吗?
更新更新更新更新更新更新更新更新更新
db.delete(TABLE_NAME, whereClause , whereArgs);
现在为android部分:
CREATE TABLE IF NOT EXISTS log (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
timestamp LONG NOT NULL
);
CREATE TABLE IF NOT EXISTS log_activity (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
log_id INTEGER NOT NULL,
activity_id INTEGER NOT NULL,
points INTEGER NOT NULL,
FOREIGN KEY(log_id) REFERENCES log(_id) ON DELETE CASCADE,
FOREIGN KEY(activity_id) REFERENCES activity(_id) ON DELETE CASCADE
);
输出:
SQLiteDatabase db = openHelper.getWritableDatabase();
db.execSQL("PRAGMA foreign_keys = ON;");
db.execSQL(CREATE_LOG); // see sql above
db.execSQL(CREATE_ACTIVITY); // not shown here, but like the sql-creates above
db.execSQL(CREATE_LOG_ACTIVITY); // see sql above
// ... insert some data ...
INSERT INTO "log" VALUES(1,1,1307797289000);
INSERT INTO "log" VALUES(2,1,1307710289000);
INSERT INTO "log" VALUES(3,2,1308089465000);
INSERT INTO "log" VALUES(4,2,1308079465000);
INSERT INTO "log_activity" VALUES(1,1,1,1);
INSERT INTO "log_activity" VALUES(2,1,2,2);
INSERT INTO "log_activity" VALUES(3,2,1,1);
INSERT INTO "log_activity" VALUES(4,2,2,2);
INSERT INTO "log_activity" VALUES(5,3,1,1);
INSERT INTO "log_activity" VALUES(6,3,2,2);
INSERT INTO "log_activity" VALUES(7,4,1,1);
INSERT INTO "log_activity" VALUES(8,4,2,2);
// check count of logs
Cursor c = db.query(false, "log", null, null, null, null, null, "_id asc", null);
android.util.Log.d("TEST", "log count before: "+c.getCount());
// check count of log_activities
Cursor c2 = db.query(false, "log_activity", null, null, null, null, null, "_id asc", null);
android.util.Log.d("TEST", "la count before: "+c2.getCount());
// delete some log-rows
long userId = 1;
int keepXLogsOfOthers = 1;
String del = "DELETE FROM log" +
" WHERE user_id != " + userId +
" AND log._id NOT IN (" +
" SELECT _id" +
" FROM (" +
" SELECT _id" +
" FROM log" +
" WHERE user_id != " + userId +
" ORDER BY timestamp DESC" +
" LIMIT " + keepXLogsOfOthers +
" ) logs_of_others_to_keep" +
");";
db.execSql(del);
// check count of logs
Cursor c3 = db.query(false, "log", null, null, null, null, null, "_id asc", null);
android.util.Log.d("TEST", "log count after: "+c3.getCount());
// check count of log_activities
Cursor c4 = db.query(false, "log_activity", null, null, null, null, null, "_id asc", null);
android.util.Log.d("TEST", "la count after: "+c4.getCount());
这意味着它自己的删除操作很好(我还检查了正确的行被删除,这解决了第一个问题!),但 ON DELETE CASCADE不起作用......为什么?
答案 0 :(得分:1)
您可以创建一个触发器来自动执行此操作。
CREATE TRIGGER [delete_log_joins]
BEFORE DELETE
ON [log]
FOR EACH ROW
BEGIN
DELETE FROM log_activity WHERE log_activity.log_id = old.id;
END
要选择删除除最新的100个日志之外的所有日志,您可以执行以下操作:
delete * from log where log.id not in (
select id
from (
select l.id
from log l
where l.id in (
select top 100 l2.id
from log l2
where l2.user_id = l.user_id
order by log.timestamp desc
)
) the_tops
);
我不确定这是多么高效,也许有人可以改进它。
答案 1 :(得分:1)
如果您有权访问数据库(创建触发器),那么SQL DELETE CASCADE是不是一个选项?
ALTER TABLE log DROP CONSTRAINT aa
ALTER TABLE log ADD CONSTRAIN
(FOREIGN KEY (log_id) REFERENCES log_activity
ON DELETE CASCADE CONSTRAINT ab)
然后使用您想要的任何子句运行您的普通JDBC删除语句。
答案 2 :(得分:0)
根据关系列设置log_id和activity_id等列。
如果它们是not_null,那么你需要根据where子句删除连接表中的行,然后删除日志和活动表中的行。
如果可以为空,则首先在连接表中将log_id和activity_id值设置为null。然后删除日志和活动表。
答案 3 :(得分:0)
通过在log_activity表上使用外键来解决问题,如下所示:
FOREIGN KEY(log_id) REFERENCES log(_id) ON DELETE CASCADE
和这样的删除声明:
long userId = 1;
int keepXLogsOfOthers = 1;
String del = "DELETE FROM log" +
" WHERE user_id != " + userId +
" AND log._id NOT IN (" +
" SELECT _id" +
" FROM (" +
" SELECT _id" +
" FROM log" +
" WHERE user_id != " + userId +
" ORDER BY timestamp DESC" +
" LIMIT " + keepXLogsOfOthers +
" ) logs_of_others_to_keep" +
");";
db.execSql(del);
不要忘记启用外键:
db.execSQL("PRAGMA foreign_keys = ON;");
我遇到的问题是模拟器没有级联log_activities ..但是在它工作的设备上。感谢其他回复者,他们给了我一些提示。
再次查看我的问题以获取更多详细信息。