Рекомендации по мягкому удалению (PHP / MySQL)

Проблема

В веб-приложении, имеющем дело с продуктами и заказами, я хочу поддерживать информацию и отношения между бывшими сотрудниками (пользователями) и заказами, которые они обрабатывали. Я хочу поддерживать информацию и отношения между устаревшими продуктами и заказами, которые включают эти продукты.

Однако я хочу, чтобы сотрудники могли убирать загроможденные интерфейсы администрирования, такие как удаление бывших сотрудников, устаревшие продукты, устаревшие группы продуктов и т. Д.

Я подумываю реализовать мягкое удаление. Итак, как это обычно делается?

Мои ближайшие мысли

Моя первая мысль - вставить столбец «flag_softdeleted TINYINT NOT NULL DEFAULT 0» в каждую таблицу объектов, которые должны быть мягко удаляемыми. Или, может быть, вместо этого использовать метку времени?

Затем я предоставляю кнопку «Показать удаленные» или «Отменить удаление» в каждом соответствующем графическом интерфейсе. Нажав на эту кнопку, вы включите в результат мягко удаленные записи. У каждой удаленной записи есть кнопка «Восстановить». Имеет ли это смысл?

Твои мысли?

Также я буду признателен за любые ссылки на соответствующие ресурсы.


person Community    schedule 16.02.2011    source источник
comment
В зависимости от размера ваших таблиц Employee / Products, может быть лучше создать отдельную таблицу с идентификаторами ваших мягко удаленных элементов.   -  person drudge    schedule 16.02.2011
comment
отметка времени всегда полезна. однако вы можете использовать все, что захотите - это не ТАКОЕ, чтобы задавать вопросы   -  person Your Common Sense    schedule 16.02.2011


Ответы (6)


Вот как я это делаю. У меня есть поле is_deleted, которое по умолчанию равно 0. Тогда запросы просто проверяют WHERE is_deleted = 0.

Я стараюсь держаться подальше от любых жестких удалений, насколько это возможно. Иногда они необходимы, но я делаю это только для администратора. Таким образом мы сможем полностью удалить, но пользователи не могут ...

Изменить. Фактически, вы можете использовать это, чтобы иметь несколько «слоев» мягкого удаления в вашем приложении. Таким образом, каждый может быть кодом:

  • 0 -> Не удалено
  • 1 -> Мягкое удаление, отображается в списках удаленных элементов для управляющих пользователей
  • 2 -> Мягкое удаление, не отображается для всех пользователей, кроме пользователей с правами администратора
  • 3 -> Отображается только для разработчиков.

Наличие двух других уровней по-прежнему позволит менеджерам и администраторам очищать удаленные списки, если они становятся слишком длинными. А поскольку внешний код просто проверяет is_deleted = 0, он прозрачен для внешнего интерфейса ...

person ircmaxell    schedule 16.02.2011
comment
Мы делаем многоуровневую иерархию для нашей внутренней CRM. Мы также используем триггер для добавления удаленной записи в резервную таблицу. Это пригодится, если кому-то когда-либо понадобится провести аудит учетной записи уровня администратора или если пользователь уровня администратора случайно удалит неправильную запись. - person Jestep; 17.02.2011
comment
ENUM, вероятно, будет лучше, чем 0,1,2,4. ENUM будет самодокументированным и столь же эффективным. - person ; 17.02.2011
comment
Будьте осторожны, чтобы вас не побили столбец uniq: ваши удаленные элементы по-прежнему будут содержать значение в столбце uniq, которое может быть не тем, что вам нужно. Но вы можете установить для этого двоеточия значение NULL при мягком удалении необработанных файлов, чтобы избежать конфликтов ... - person Julien Palard; 22.05.2014
comment
что, если обычный пользователь мягко удалит родительскую запись, у которой есть дочерние записи. В таком случае родительская запись и все ее дочерние элементы будут скрыты от обычных пользователей. Это точно так же, как и проблема с каскадным удалением. Итак, мой вопрос в том, как проверить ссылочную целостность перед мягким удалением родительских записей? - person manas; 21.12.2016
comment
также вы можете использовать дополнительное поле (или заменить его) как дату и время / метку времени, чтобы узнать, когда строка была удалена - person JorgeGarza; 20.09.2017

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

  • Сохранение данных пользователя, когда они что-то удалили
  • Сохранение собственных данных при удалении чего-либо
  • Записывайте, что произошло на самом деле (своего рода аудит)
  • и так далее

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

Есть разные степени удалений. Типичный пользователь удаляет данные, когда он

  • Сделал ошибку и хочу удалить неверные данные
  • Больше не хочет что-то видеть на экране

Проблема в том, что если вы не записываете намерение удаления, ваше приложение не сможет различить ошибочные данные (которые никогда не должны были создаваться) и исторически правильные данные.

Взгляните на следующие данные:

PRICES | item | price | deleted |
       +------+-------+---------+
       |   A  |  101  |    1    |
       |   B  |  110  |    1    |
       |   C  |  120  |    0    |
       +------+-------+---------+

Некоторые пользователи не хотят показывать цену предмета Б, поскольку он больше не продает этот предмет. Поэтому он его удаляет. Другой пользователь создал цену для предмета A путем ошибочной ставки, поэтому он удалил его и создал цену для предмета C, как и предполагалось. А теперь можете показать мне список цен на все продукты? Нет, потому что либо вы должны отображать потенциально ошибочные данные (A), либо вам нужно исключить все, кроме текущих цен (C).

Конечно, с вышеизложенным можно справиться разными способами. Я считаю, что ВЫ должны четко понимать, что ВЫ подразумеваете под удалением, и следить за тем, чтобы пользователи не могли это неправильно понять. Один из способов - заставить пользователя сделать выбор (скрыть / удалить).

person Ronnis    schedule 16.02.2011

Если бы у меня был существующий код, который попадает в эту таблицу, я бы добавил столбец и изменил имя таблицы. Затем я бы создал представление с тем же именем, что и текущая таблица, которое выбирает только активные записи. Таким образом, ни один из существующего кода не сломается, и у вас может быть столбец мягкого удаления. Если вы хотите увидеть удаленную запись, вы выбираете ее из базовой таблицы, в противном случае вы используете представление.

person HLGEM    schedule 16.02.2011
comment
Хотя кратко, я бы принял это решение. В принципе, это применимо к реальным производственным базам данных и ОПРЕДЕЛЕННО подходит. Никто не захочет иметь удаленный столбец и будет склонен просто забывать о добавлении условия, в котором удалено = 0, в один из многих запросов, которые будут использоваться в приложении. - person MohamedEzz; 24.05.2014

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

Некоторые компоненты, которые я создаю, позволяют пользователю просматривать все удаленные записи и восстанавливать их, другие просто отображают все записи, где удалено = 0

person simshaun    schedule 16.02.2011

Ваша идея имеет смысл и часто используется в производстве, но для ее реализации вам потребуется обновить довольно много кода, чтобы учесть новое поле. Другой вариант - заархивировать (переместить) записи с обратимым удалением в отдельную таблицу или базу данных. Это также делается часто, и проблема заключается в обслуживании, а не в (перепрограммировании). (У вас может быть триггер таблицы, реагирующий на удаление, чтобы заархивировать удаленную запись.)

Я бы сделал архивирование, чтобы избежать серьезного обновления производственного кода. Но если вы хотите использовать поле удаленного флага, используйте его как метку времени, чтобы предоставить вам дополнительную полезную информацию помимо логического. (Null = не удалено.) Вы также можете добавить поле DeletedBy для отслеживания пользователя, ответственного за удаление записи. Использование двух полей дает вам много информации о том, кто что удалил и когда. (Решение с двумя дополнительными полями также можно сделать в архивной таблице / базе данных.)

person Paul Sasik    schedule 16.02.2011

Самый распространенный сценарий, с которым я столкнулся, - это то, что вы описываете, tinyint или даже bit, представляющие состояние IsActive или IsDeleted. В зависимости от того, считаются ли это «бизнес-данными» или «постоянными» данными, они могут быть встроены в логику приложения / домена настолько прозрачно, насколько это возможно, например, непосредственно в хранимых процедурах и неизвестно коду приложения. Но похоже, что это законная бизнес-информация для ваших нужд, поэтому ее необходимо знать во всем коде. (Таким образом, пользователи могут просматривать удаленные записи, как вы предлагаете.)

Другой подход, который я видел, - это использование комбинации двух временных меток для отображения «окна» активности для данной записи. Это немного больше кода для его поддержки, но преимущество в том, что что-то может быть запланировано на мягкое удаление самого себя в заранее определенное время. Таким образом, например, можно настроить продукты с ограниченным сроком действия при их создании. (Чтобы сделать запись активной на неопределенный срок, можно использовать максимальное значение (или просто какую-то абсурдно отдаленную дату в будущем) или просто указать дату окончания null, если вас это устраивает.)

Затем, конечно, есть дальнейшее рассмотрение того, что время от времени удаляется / восстанавливается, и отслеживается какой-то аудит для этого. Подход с флагом знает только текущий статус, подход с отметкой времени знает только самое последнее окно. Но что-либо столь сложное, как контрольный журнал, определенно следует хранить отдельно от рассматриваемых записей.

person David    schedule 16.02.2011
comment
В MySQL есть BIT ?? Я всегда использовал TINYINT. поразительно В чем разница между использованием BIT и TINYINT для логического поля? - person ; 16.02.2011
comment
@ arex1337: bit фактически использовалось как синоним tinyint в MySQL: dev.mysql.com/doc/refman/5.0/en/numeric-type-overview.html Возможно, вам лучше будет tinyint, но не цитируйте меня по этому поводу. В некоторых других базах данных одно ключевое отличие состоит в том, что bit нельзя индексировать или обрабатывать null по-разному (или не обрабатывать вообще) и т. Д. Но у меня недостаточно прямых знаний о типах данных, чтобы MySQL действительно мог это. - person David; 16.02.2011