Предотвращение дублирования записей в SQL Server - PullRequest
0 голосов
/ 29 июля 2011

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

Вот как выглядит оператор вставки:

IF NOT EXISTS (SELECT * FROM tblMessages WHERE message = @message and ip = @ip and datediff(minute,timestamp, getdate()) < 10)
    BEGIN
        INSERT INTO tblMessages (ip, message, votes, latitude, longitude, location, timestamp, flags, deleted, username, parentId)
        VALUES (@ip, @message, 0, @latitude, @longitude, @location, GETDATE(), 0, 0, @username, @parentId)
    END

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

Как я могу предотвратить это правильно?

Ответы [ 4 ]

1 голос
/ 29 июля 2011

Я полагаю, вам нужен триггер

Уникальное ограничение / индекс недостаточно умен, чтобы справиться с 10-минутным промежутком между сообщениями для данного сообщения и ip.

CREATE TRIGGER TRG_tblMessages_I FRO INSERT
AS
SET NOCOUNT ON;

IF EXISTS (SELECT * 
       FROM tblMessages M
           JOIN INSERTED I ON M.message = I.message and M.ip = I.ip
       WHERE
           datediff(minute, M.timestamp, I.timestamp) < 10)
BEGIN
    RAISERRROR ('blah', 16, 1)
    ROLLBACK TRAN
END

Редактировать: вам нужно дополнительное условие, чтобы игнорировать ту же строку, которую вы только что вставили (например, используя суррогатный ключ)

1 голос
/ 29 июля 2011

На самом деле Дерек Кромм не за горами; По сути, вы хотите уникальное ограничение, вам просто нужен диапазон для одного из столбцов.

Вы можете выразить это как отфильтрованный индекс , который обеспечивает уникальность нужных столбцов, но с фильтром для сопоставления временных меток в диапазоне 10 минут.

CREATE NONCLUSTERED INDEX IX_UNC_tblMessages
ON tblMessages (message, ip, timestamp)
WHERE datediff(minute, timestamp, getdate()) < 10)

О разнице между уникальным ограничением и фильтрованным индексом, который поддерживает уникальность ( MSDN ):

Нет существенных различий между созданием УНИКАЛЬНЫХ ограничение и создание уникального индекса, независимого от ограничения. Проверка данных происходит таким же образом, а оптимизатор запросов - не делать различий между уникальным индексом, созданным ограничением или созданный вручную. Тем не менее, вы должны создать уникальный или первичный ключ ограничение на столбец, когда целью является целостность данных. От При этом цель индекса будет ясна.

Единственный аспект этого, в котором я не уверен, это использование getdate (). Я не уверен, какое влияние это окажет на индекс и производительность - это вы сами захотите проверить.

0 голосов
/ 29 июля 2011

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

или, как сказал Дерек, вы можете использовать ограничение, но с другимусловие:

ALTER TABLE tblMessages ADD CONSTRAINT uq_tblMessages UNIQUE (message,ip,username, parentId)

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

0 голосов
/ 29 июля 2011

Добавить уникальное ограничение к таблице, чтобы оно полностью исключалось

ALTER TABLE tblMessages ADD CONSTRAINT uq_tblMessages UNIQUE (message,ip,timestamp)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...