Что сделать, когда я хочу использовать ограничения базы данных, но только отметить, как удалено вместо удаления?

Помните, что Google Play занимает некоторое время, чтобы опубликовать новую версию в магазине Play. Потому что он проверяет каждый раз, когда вы загружаете новый APK. Предыдущий APk будет сохранен после запуска нового apk.

6
задан Shalom Craimer 21 April 2009 в 05:55
поделиться

10 ответов

Вы можете добавить значение id в конец имени, когда запись удаляется, поэтому, когда кто-то удаляет идентификатор 3, имя становится Thingy3_3, а затем, когда он удаляет идентификатор 100, имя становится Thingy3_100. Это позволило бы вам создать уникальный составной индекс по имени и удаленным полям, но затем вам придется фильтровать столбец имени при каждом его отображении и удалять идентификатор из конца имени.

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

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

Вы могли бы реализовать всю эту логику в базе данных, используя триггер INSTEAD-OF для удаления. Этот триггер не будет удалять записи, но вместо этого обновит столбец delete_at при удалении записи.

Следующий пример кода демонстрирует это

CREATE TABLE swtest (  
    id          INT IDENTITY,  
    name        NVARCHAR(20),  
    deleted_at  DATETIME  
)  
GO  
CREATE TRIGGER tr_swtest_delete ON swtest  
INSTEAD OF DELETE  
AS  
BEGIN  
    UPDATE swtest SET deleted_at = getDate()  
    WHERE id IN (SELECT deleted.id FROM deleted)
    AND deleted_at IS NULL      -- Required to prevent duplicates when deleting already deleted records  
END  
GO  

CREATE UNIQUE INDEX ix_swtest1 ON swtest(name, deleted_at)  

INSERT INTO swtest (name) VALUES ('Thingy1')  
INSERT INTO swtest (name) VALUES ('Thingy2')  
DELETE FROM swtest WHERE id = SCOPE_IDENTITY()  
INSERT INTO swtest (name) VALUES ('Thingy2')  
DELETE FROM swtest WHERE id = SCOPE_IDENTITY()  
INSERT INTO swtest (name) VALUES ('Thingy2')  

SELECT * FROM swtest  
DROP TABLE swtest  

. Выбор из этого запроса возвращает следующее

id      name       deleted_at
1       Thingy1    NULL
2       Thingy2    2009-04-21 08:55:38.180
3       Thingy2    2009-04-21 08:55:38.307
4       Thingy2    NULL

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

12
ответ дан 8 December 2019 в 05:57
поделиться

Для простой таблицы с именем [Test] с идентификаторами столбцов (int), Filter (nvarchar), Deleted ( бит)

ALTER TABLE [dbo].[Test] ADD 
    CONSTRAINT [DF_Test_Deleted] DEFAULT (0) FOR [Deleted],
    CONSTRAINT [IX_Test] UNIQUE  NONCLUSTERED 
    (
        [filter],
        [Deleted]
    )  ON [PRIMARY] 
1
ответ дан 8 December 2019 в 05:57
поделиться

Возможно, стоит подумать об использовании таблицы «Корзина». Вместо того чтобы хранить старые записи в той же таблице с флагом, переместите их в свою собственную таблицу со своими собственными ограничениями. Например, в активной таблице у вас есть ограничение UNIQUE на имя, а в таблице корзины - нет.

3
ответ дан 8 December 2019 в 05:57
поделиться

Проблема с составным уникальным ограничением состоит в том, что невозможно удалить несколько записей с одинаковым именем. Это означает, что система сломается, как только вы удалите третью запись. Я бы не рекомендовал добавлять материал к именам, потому что теоретически может возникнуть дублирующая ситуация. Кроме того, тем самым вы в основном повреждаете данные в базе данных, а также добавляете загадочную бизнес-логику к самим данным.

Единственное возможное решение для всей базы данных - это добавить триггер, который проверяет, что вставленный / обновленный данные действительны. Также возможно поместить проверки вне базы данных в код.

2
ответ дан 8 December 2019 в 05:57
поделиться

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

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

1
ответ дан 8 December 2019 в 05:57
поделиться

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

Редактировать после комментария: Вы можете просто добавить подчеркивание и текущую метку времени.

1
ответ дан 8 December 2019 в 05:57
поделиться

Не конечно же, в SQLServer2005, но вы можете определить составные ограничения / индексы

CREATE UNIQUE INDEX [MyINDEX] ON [TABLENAME] ([NAME] , [DELETED])

Как указал SteveWeet, это позволит вам только удалить / создать дважды.

0
ответ дан 8 December 2019 в 05:57
поделиться

Тип ограничения, который вам нужен - это ограничение CHECK на уровне таблицы, т.е. ограничение CHECK, состоящее из подзапроса, который проверяет NOT EXISTS (или эквивалент) для таблицы, например,

CREATE TABLE Test 
(
   ID INTEGER NOT NULL UNIQUE, 
   name VARCHAR(30) NOT NULL, 
   deleted INTEGER NOT NULL, 
   CHECK (deleted IN (0, 1))
);

ALTER TABLE Test ADD
   CONSTRAINT test1__unique_non_deleted
      CHECK 
      (
         NOT EXISTS 
         (
            SELECT T1.name
              FROM Test AS T1
             WHERE T1.deleted = 0
             GROUP
                BY T1.Name
            HAVING COUNT(*) > 1
         )
      );

INSERT INTO Test (ID, name, deleted) VALUES (1, 'Thingy1', 0)
;
INSERT INTO Test (ID, name, deleted) VALUES (2, 'Thingy2', 0)
;
INSERT INTO Test (ID, name, deleted) VALUES (3, 'Thingy3', 1)
;
INSERT INTO Test (ID, name, deleted) VALUES (4, 'Thingy3', 1)
;
INSERT INTO Test (ID, name, deleted) VALUES (5, 'Thingy3', 0)
;
INSERT INTO Test (ID, name, deleted) VALUES (6, 'Thingy3', 0)
;

Последний INSERT (ID = 6) заставит ограничение сработать и INSERT будет провален. Q.E.D.

... ох, чуть не забыл упомянуть: SQL Server пока не поддерживает CHECK ограничения, содержащие подзапрос (я тестировал вышеописанное на ACE/JET, a.k.a. ). Хотя вы могли бы использовать ФУНКЦИЮ, я читал, что это небезопасно из-за того, что SQL Server тестирует ограничения по строкам (см. блог Дэвида Портаса). Пока эта функция SQL-92 не будет полностью поддерживаться в SQL Server, я предпочитаю использовать ту же логику в триггере.

1
ответ дан 8 December 2019 в 05:57
поделиться

Создать уникальное ограничение для (имя удалено). Однако это будет означать, что вы можете удалить только одно имя.

Очевидный обходной путь для , который работает под ANSI-92, но не на MS SQLServer: https: // connect. microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=299229

0
ответ дан 8 December 2019 в 05:57
поделиться

Вместо удаленного столбца используйте столбец end_date. Когда пользователь удаляет запись, добавьте текущую дату в столбец end_date. Любые записи, в которых столбец end_date равен NULL, являются вашими текущими записями. Определите уникальное ограничение для двух столбцов name и end_date. Из-за этого ограничения у вас никогда не будет сценария, в котором правильное имя записи будет продублировано. Каждый раз, когда пользователь хочет восстановить запись, вам нужно установить для столбца end_date значение null, и если это нарушает ограничение уникальности, вы показываете пользователю сообщения, что такое имя уже существует.

1
ответ дан 8 December 2019 в 05:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: