Модераторы: skyboy
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> MySQL: Удалить часть строк из таблицы 
:(
    Опции темы
rcdimon
Дата 11.2.2009, 16:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 766
Регистрация: 12.7.2004
Где: Москва

Репутация: нет
Всего: 2



У меня есть таблица- журнал действий пользователей. Необходимо один раз в сутки исполнять запрос, который будет очищать таблицу, оставляя по 20 последних определенных действий каждого пользователя. Таблица такого вида

id - Номер строки (autoincrement)
user_id - Номер пользователя
action - Номер действия

Надо оставлять действия следующих номеров (250, 255, 257, 306, 310, 322, 350, 354, 551, 553, 562, 563), остальные удалять, даже если они входят в двадцатку последних.

Заранее спасибо.
PM MAIL ICQ   Вверх
Akina
Дата 11.2.2009, 17:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



То есть должны остаться по 20 записей каждого действия из перечисленных для каждого из пользователей, а остальное в корзину? Мрачный запрос... я бы наоборот, скопировал то, что надо оставить, во временную таблицу, очистил бы рабочую и вернул в неё сохранённые записи.




--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
rcdimon
Дата 11.2.2009, 17:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 766
Регистрация: 12.7.2004
Где: Москва

Репутация: нет
Всего: 2



Ну тогда помоги с запросом, который скопирует нужное ) 
PM MAIL ICQ   Вверх
Gluttton
Дата 11.2.2009, 17:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начинающий
***


Профиль
Группа: Завсегдатай
Сообщений: 1170
Регистрация: 28.8.2008
Где: Феодосия

Репутация: 24
Всего: 54



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

Код

SELECT A.id, A.user_id, A.action
FROM X AS A
    WHERE A.id>=
    (
        SELECT MAX(B.id)-20
        FROM X as B
    )
    AND action IN
    (
        '250', '255', '257'
    )


По хорошему в существующую таблицу необходимо добавить колонку, что то вроде time, которая бы хранила время операции, тогда можно было бы предложить более коректное решение.

А если таблица общая (в смысле одна на всех пользователей, а оно судя по всему так и есть), а необходимо выводить последние 20 событий для КАЖДОГО пользователя, то тогда это уже будет несколько другое решение.

Добавлено через 6 минут и 16 секунд
Код

DELETE FROM X
WHERE X.id NOT IN
(
SELECT A.id
FROM X AS A
    WHERE A.id>=
    (
        SELECT MAX(B.id)-20
        FROM X as B
    )
    AND action IN
    (
        '250', '255', '257'
    )
)


Внимательно прочитав вопрос, понял, что не совсем то написал (или совсем не то)  smile .
Так лучше?


--------------------
Слава Україні!
PM MAIL   Вверх
Akina
Дата 11.2.2009, 17:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Цитата(Gluttton @  11.2.2009,  18:40 Найти цитируемый пост)
Вот пример некоректного решения

Это неверное решение. Запрос выберет записи указанного типа из 20 последних записей. То есть их ВСЕГО будет не более 20, а скорее всего меньше, если среди последних 20 есть записи другого типа...

rcdimon, подходить к запросу можно, скажем, так: сначала надо получить все пары юзер+тип
Код

select distinct user_id, action 
from table
where action in (250, 255, 257, 306, 310, 322, 350, 354, 551, 553, 562, 563)

Далее надо построить запрос, который для каждой группы отсортирует события по уменьшению ID, пронумерует их в группе вычисляемым полем и отберёт те записи, у которых это вычисляемое поле будет не более 20. Можно копировать полученную выборку во временную таблицу, либо модифицировать, отбирая записи с  вычисляемым полем более 20 и использовать IDы как условие отбора в запросе на удаление. Но в любом случае это будет монстроидальный запрос, которы будет жеваться сервером долго и нудно.

Я же полагаю, что есть смысл пойти по пути создания хранимой процедуры - получив в ней результат вышенаписанного запроса, идём по нему с курсором и выгребаем IDы по условию order by ID DESC limit 20 записей для каждой записи из этого запроса, сваливая их во временную таблицу. После чего заключительным аккордом связываем временную таблицу с основной и выполняем удаление по условию отсутствия ID во временной таблице.

В любом случае жутик.
=============
Но вообще я бы делал совершенно иначе. Завёл бы поле действительности записи. И каждый раз при внесении в таблицу очередной записи о событии для заданного события и юзера все аналогичные записи кроме последних 20 в этом поле помечал бы крестиком. Оформить лучше всего триггером, чтобы не засорять сами фиксирующие запросы. Тогда очистка таблицы станет делом совершенно тривиальным - просто давим всё, что имет крестик в поле действительности. А если ещё создать табличку, которая установит соответствие между, скажем, типом события и количеством оставляемых непомеченными записей данного события для каждого юзера - процесс руления очисткой станет более гибким и динамичным.
Кроме того, нагрузка по очистке таблицы фактически будет размазана по всему периоду её наполнения, что благоприятно скажется на производительности системы.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
rcdimon
Дата 11.2.2009, 18:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 766
Регистрация: 12.7.2004
Где: Москва

Репутация: нет
Всего: 2



А, например, вынуть из лога список пользователей, чьи события там присутствуют, а потом программой в цикле для каждого пользователя провети удаления, оставляя последние 20 записей? Долго наверное будет при большом числе пользователей....
PM MAIL ICQ   Вверх
Gluttton
Дата 11.2.2009, 18:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начинающий
***


Профиль
Группа: Завсегдатай
Сообщений: 1170
Регистрация: 28.8.2008
Где: Феодосия

Репутация: 24
Всего: 54



to Akina

Цитата

Это неверное решение. Запрос выберет записи указанного типа из 20 последних записей.


Однозначно согласен  smile .

Ниже привожу "крокодила" претендующего на звание правильного, но не коректного решения.

Код

DELETE FROM X
WHERE X.id NOT IN
(
    SELECT SubA.id
    FROM
    (
       SELECT * FROM X WHERE X.action IN (250, 255, 257, 306, 310, 322, 350, 354, 551, 553, 562, 563)
    )   AS SubA
        WHERE 
        (
            SELECT COUNT(SubB.id) AS c
            FROM 
            (
               SELECT * FROM X WHERE X.action IN (250, 255, 257, 306, 310, 322, 350, 354, 551, 553, 562, 563)
            )   AS SubB, SubA
                WHERE SubB.id>=SubA.id
        )<=20
)




--------------------
Слава Україні!
PM MAIL   Вверх
rcdimon
Дата 11.2.2009, 18:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 766
Регистрация: 12.7.2004
Где: Москва

Репутация: нет
Всего: 2



Что некорректного то.. autoincrement каждый следующий всегда больше предыдущего. Удаляй ты записи из таблицы или нет.... Если id у записи больше- однозначно можно сказать, что она была добавлена позже. А поле со временем у меня в таблице есть DATETIME
PM MAIL ICQ   Вверх
Akina
Дата 11.2.2009, 18:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Цитата(Gluttton @  11.2.2009,  19:31 Найти цитируемый пост)
Ниже привожу "крокодила" претендующего на звание правильного, но не коректного решения.

На более-менее приличной базе от запроса такого рода сервер уйдёт в штопор.



--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
rcdimon
Дата 11.2.2009, 19:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 766
Регистрация: 12.7.2004
Где: Москва

Репутация: нет
Всего: 2



Мне понравилась идея про метку того, что эту запись можно удалять.
Единственное возникла проблема с запросом на установку метки )

Перед записью новой строки в таблицу, запрос находит 20-ую по новизне запись и ставит метку. Запрос который пришел в голову такой

Код

UPDATE
    `log`
SET 
    `fordrop` = 1
WHERE
            `user_id` = 1
ORDER BY `id` DESC
LIMIT 20,1    



Но мне благополучно выдается ошибка 

Цитата

#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '1' at line 8


Добавлено через 2 минуты и 4 секунды
а в таком

Код

UPDATE
    `mob_log`
SET 
    `fordrop` = 1
WHERE
    `id` = (
        SELECT `id`
        FROM `mob_log`
        WHERE `user_id` = 1
        ORDER BY `id` DESC
        LIMIT 20,1
    )



такая  smile 

Цитата

#1093 - You can't specify target table 'mob_log' for update in FROM clause

PM MAIL ICQ   Вверх
Dobermann
Дата 11.2.2009, 19:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 992
Регистрация: 7.1.2008

Репутация: нет
Всего: 0



Цитата(rcdimon @  11.2.2009,  19:04 Найти цитируемый пост)
Но мне благополучно выдается ошибка 

Попробуйте единичку в кавычки взять...

PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Составление SQL-запросов | Следующая тема »


 




[ Время генерации скрипта: 0.0554 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.