Проблема с SQL (INSERT с одинаковыми значения)

Рейтинг: 2Ответов: 2Опубликовано: 17.07.2023

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

Есть таблица, например:

|ID|Поле1|Поле2|Поле3
|--|-----|-----|-----
|1 |    а|    а|   а|
|2 |    a|    a|   b|

При вставке значений в таблицу нужно чтобы при совпадении ВСЕХ данных (3 одинаковых значения для 3 полей) вставка НЕ происходила, но при совпадении некоторых данных (1 или 2 одинаковых значения для 1 или 2 полей) вставка происходила.

PRIMARY KEY есть только у ID.

Например:

  1. Вставляю a a a или a a b- таблица не должна изменяться

  2. Вставляю a a c или a b b - новые записи должны появляться в таблице

Ответы

▲ 1Принят

Можно создать индекс с набором уникальных полей. Например:

CREATE UNIQUE INDEX idx_unique_fields ON table_name (Поле1, Поле2, Поле3);

При вставке строки с повторяющимися значениями полей, вставка происходить не будет. Если по каким-то причинам нужно вставить строку, даже если они имеют некоторые одинаковые значения в полях, рекомендую воспользоваться условием ON CONFLICT DO NOTHING. Например:

INSERT INTO your_table_name (Поле1, Поле2, Поле3)
VALUES ('a', 'a', 'c')
ON CONFLICT (Поле1, Поле2, Поле3) DO NOTHING;

Такой подход решает проблему?

▲ 2

Вижу 3 варианта решения данной проблемы без создания уникальных индексов на несколько полей:

Для начала объявлю таблицу для примера:

    CREATE TABLE [dbo].[TestTable](
        [id] [int] NOT NULL,
        [value1] [nchar](10) NOT NULL,
        [value2] [nchar](10) NOT NULL
    ) ON [PRIMARY]

1.Самый банальный и простой вариант, как по мне

DECLARE
@IdValue int,
@FirstValue nchar(10),
@SecondValue nchar(10)

SELECT @IdValue = 1,
@FirstValue = 'a',
@SecondValue = 'b'

INSERT INTO TestTable 
SELECT @IdValue, @FirstValue, @SecondValue
WHERE NOT EXISTS(SELECT 1 FROM TestTable t WHERE t.value1 
= @FirstValue AND t.value2 = @SecondValue AND t.id != @IdValue) 

2.Костыль, если у Вас уже есть готовая система - удаление строки в случае "неудачного" варианта:

CREATE TRIGGER InsertDelete
ON TestTable
AFTER INSERT
AS
BEGIN
DECLARE
@IdValue int,
@FirstValue nchar(10),
@SecondValue nchar(10)
SELECT @IdValue = INSERTED.[id],
@FirstValue= INSERTED.[value1],
@SecondValue= INSERTED.[value2]
FROM INSERTED

    IF EXISTS(SELECT 1 FROM TestTable t WHERE t.value1 = @FirstValue AND t.value2 = @SecondValue AND t.id != @IdValue) 
    BEGIN
        DELETE FROM TestTable WHERE id = @IdValue
    END;
END

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

С первичным ключом я не рекомендую использовать Delete, т.к. это несет последствия, но целостность при нормальном использовании нарушить не должно

  1. Вы можете попробовать использовать INSTEAD OF TRIGGER. Здесь более подробно написано как это сделать: ТЫК (сам никогда не использовал его, поэтому предоставляю ссылку на оригинал)