#sql #sqlite
#sql #sqlite
Вопрос:
Поэтому при создании таблицы я хотел бы добавить условие, гарантирующее, что две строки не полностью идентичны, не принимая идентификатор в счет. Таким образом, один или несколько столбцов могут быть одинаковыми, но не полная строка. Возможно ли это? В идеале я хотел бы, чтобы метод (если он есть) работал в SQLite.
Большое спасибо.
Ответ №1:
Если все столбцы (кроме первичного ключа) вашей таблицы были определены как NOT NULL
тогда UNIQUE
ограничение для всех столбцов:
CREATE TABLE tablename (
id INTEGER PRIMARY KEY,
col1 TEXT NOT NULL,
col2 TEXT NOT NULL,
col3 TEXT NOT NULL,
UNIQUE(col1, col2, col3)
);
было бы достаточно, чтобы гарантировать, что все строки уникальны.
Но для такой таблицы, как эта:
CREATE TABLE tablename (
id INTEGER PRIMARY KEY,
col1 TEXT,
col2 TEXT,
col3 TEXT
);
ограничение unique не будет перехватывать 2 строки, например:
id col1 col2 col3
--------------------
1 a b null
2 a b null
потому null
что s не считаются равными.
Вам нужно 2 триггера, один BEFORE INSERT
и другой BEFORE UPDATE
:
CREATE TRIGGER unique_row_tablename_insert BEFORE INSERT ON tablename
BEGIN
SELECT
CASE WHEN EXISTS (
SELECT 1 FROM tablename t
WHERE t.col1 IS NEW.col1 AND t.col2 IS NEW.col2 AND t.col3 IS NEW.col3
) THEN RAISE (ABORT, 'The row already exists')
END;
END;
CREATE TRIGGER unique_row_tablename_update BEFORE UPDATE ON tablename
BEGIN
SELECT
CASE WHEN EXISTS (
SELECT 1 FROM tablename t
WHERE t.id <> NEW.id AND t.col1 IS NEW.col1 AND t.col2 IS NEW.col2 AND t.col3 IS NEW.col3
) THEN RAISE (ABORT, 'The row already exists')
END;
END;
Используя оператор IS
вместо =
вы можете сопоставить null
s как равный.
Эти триггеры вызовут ошибку с сообщением: 'The row already exists'
и прервут операцию, если новая / обновленная строка соответствует уже существующей строке.
Ответ №2:
Добавьте уникальный индекс в вашу таблицу для всех столбцов:
CREATE UNIQUE INDEX idx ON yourTable (col1, col2, ..., colN); -- assuming N columns
При наличии этого индекса любая попытка вставить запись, все значения которой соответствуют записи, уже имеющейся в таблице, завершится ошибкой.
Комментарии:
1. Хотя a
UNIQUE INDEX
, безусловно, выполнит эту работу, обычно вы определяете уникальное ограничение , напримерCONSTRAINT <name> UNIQUE (col1, col2, col3, ...)
, как часть определения таблицы.2. @TheImpaler . , , я бы не сказал, что один метод используется чаще, чем другой. Они реализованы одинаково. Преимущество ограничения в том, что вы можете присвоить ограничению имя. (Но опять же, преимущество индекса в том, что вы можете присвоить индексу имя.)
3. Ни ограничение, ни индекс не будут работать в случае, если есть столбцы с
null
s, потомуnull
что s не считаются равными друг другу.4. Обратите внимание, что SQLite рассматривает строки
(null, null)
и(null, null)
как разные.