SQL удалить из одной таблицы + стол соединения? - PullRequest
5 голосов
/ 16 июня 2011

У меня есть три таблицы: log, activity и объединяемая таблица (many2many) log_activitylog_id и activity_id + дополнительные данные в виде столбцов).

Я хочу удалить из log и log_activity.

Я хочу сохранить все журналы от определенного пользователя и сохранить только 100 строк от других пользователей. Это означает, что я хочу удалить все строки, которые соответствуют WHERE log.user_id != 1, но последние 100 (ORDER BY log.timestamp DESC).

Я также хочу удалить из объединяемой таблицы log_activity все записи, относящиеся к журналам, которые удаляются. Стол activity должен не быть затронутым.

Я думаю, что db.delete(TABLE_NAME, whereClause , whereArgs); не поможет в этом случае ..

Так может ли кто-нибудь придумать эффективное решение?


ОБНОВЛЕНИЕ ОБНОВЛЕНИЕ ОБНОВЛЕНИЕ ОБНОВЛЕНИЕ ОБНОВЛЕНИЕ ОБНОВЛЕНИЕ ОБНОВЛЕНИЕ ОБНОВЛЕНИЕ ОБНОВЛЕНИЕ


Вдохновленный ответами Джейкоба Эггерса и плафона, и дальнейшими исследованиями я сейчас пытаюсь вот так, но пока это не работает:

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
);

Теперь для android части:

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());

выход:

06-16 10:40:01.748: DEBUG/TEST(451): log count before: 4
06-16 10:40:01.748: DEBUG/TEST(451): la count before: 8
06-16 10:40:01.828: DEBUG/TEST(451): log count after: 3
06-16 10:40:01.838: DEBUG/TEST(451): la count after: 8

Это означает, что операция DELETE сама по себе хороша (я также проверил, что правильные строки удалены, что решает первую проблему !!), но ON DELETE CASCADE не работает ... почему?

Ответы [ 4 ]

1 голос
/ 16 июня 2011

Если у вас есть доступ к БД (создание триггера), тогда 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, используя любое предложение.

1 голос
/ 16 июня 2011

Вы можете создать триггер, чтобы сделать это автоматически.

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
);

Я не уверен, насколько это эффективно, может быть, кто-то может улучшить его.

0 голосов
/ 20 июня 2011

Решил проблему с помощью внешнего ключа в таблице 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 .. но на устройстве это работает. Спасибо другим ответчикам, которые дали мне несколько подсказок.

См. Мой вопрос снова для более подробной информации.

0 голосов
/ 16 июня 2011

В зависимости от отношений устанавливаются столбцы, такие как log_id и activity_id.

если они не_нульные, вам нужно удалить строки в таблице соединений на основе вашего предложения where, а затем удалить строки в таблицах журналов и операций.

если они обнуляются, вы сначала установите значения log_id и activity_id в таблице соединений равными нулю. Затем удалите журналы и таблицы активности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...