SQL Server: триггер обновления, похоже, влияет на неправильный столбец - PullRequest
0 голосов
/ 29 сентября 2018

Спасибо за поиск.Я пытаюсь написать триггер SQL Server, который при добавлении новой записи, содержащей информацию о дате, добавит день недели в столбец DayOfWeek.Вот моя таблица со столбцами в следующем порядке:

Таблица еды:

FoodName **varchar(20)**  
CategoryID (FK) **int**  
Price **smallmoney**  
StoreID (FK) **int**  
Date **datetime**  
DayOfWeek **varchar(9)**  
ShopperID (FK) **int**  
Week **int**  

Вот триггер, который я написал:

-- Create a trigger to update day of the week when a record is inserted  
CREATE TRIGGER DOW  
ON Food  
FOR INSERT  
AS  
BEGIN  
    -- Declare a variable to hold the date ID  
    DECLARE @dateID DATETIME

    -- Get the date from the new record and store it in @dateID  
    SELECT @dateID = Date FROM Food  

    -- Insert day of the week based on the inserted date  
    INSERT INTO Food (DayOfWeek)  
        SELECT DATENAME(dw, @dateID)  
END  
GO  

Казалось, что SQL Serverпринять процедуру, но когда я запустил другую процедуру для вставки новой записи, я получил эту ошибку:

Сообщение 515, Уровень 16, Состояние 2, Процедура DOW, Строка 8 [Стартовая строка 21]
Невозможно вставить значение NULL в столбец «Неделя», таблица *******;столбец не допускает пустых значений.Вставить не удается.

Я не уверен, почему этот триггер вообще влияет на столбец «Неделя».Код должен принимать значение, введенное для Date, и использовать функцию DATENAME (dw, ...), чтобы вернуть день недели, который должен войти в столбец DayOfWeek.Я написал хранимую процедуру, которая принимает дату в качестве входных данных и вставляет в запись соответствующий день недели, и она работает просто отлично, но этот триггер, похоже, не хочет сотрудничать.Я в тупике!

Ответы [ 2 ]

0 голосов
/ 30 сентября 2018

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

This is bad because a trigger can have multiple rows
This SQL simply will not work correctly if you insert multiple rows.
DECLARE @dateID DATETIME
SELECT @dateID = Date FROM Food  

This SQL is trying to insert a new row which is causing your NULL error
It is not trying to update the row you are inserting
INSERT INTO Food (DayOfWeek)  
    SELECT DATENAME(dw, @dateID)  

Это должен быть триггер INSTEAD OF, чтобы избежать ограничения NULL на столбец.Ответ Вольфганга по-прежнему вызовет нулевую ошибку ограничения, потому что после запуска триггеров ПОСЛЕ, данные вставляются.Триггер INSTEAD OF будет работать вместо фактической вставки.

CREATE TRIGGER DOW ON Food
INSTEAD OF INSERT
AS
BEGIN
    SET NOCOUNT ON;
    -- update the day of the week for the inserted rows

    INSERT INTO Food (FoodName,CategoryID,Price,StoreID,[Date],ShopperID,[Week],[DayOfWeek])
        SELECT
            FoodName,CategoryID,Price,StoreID,[Date],ShopperID,[Week],DATENAME(dw, [Date]) AS [DayOfWeek]
        FROM inserted
END
GO

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

0 голосов
/ 29 сентября 2018

Что делает ваш триггер:

  • он извлекает Date из вашей таблицы (последней возвращаемой), которая не обязательно является последним вставленным значением.
  • itпытается вставить новую запись, указав только DayOfWeek из указанного Date.
  • не удастся, поскольку необходимо указать хотя бы Week.

IПредположим, что вы хотите обновить значение DayOfWeek для вставленных строк.Чтобы иметь возможность сделать это, должен быть способ идентифицировать строки, которые необходимо обновить в таблице Food, зная значения вставленных строк.Чтобы быть уверенным в обновлении правильных строк, должен быть первичный ключ, позволяющий идентифицировать их.Конечно, у вас есть такой первичный ключ, и я предполагаю, что он называется FoodID, поэтому, вероятно, вы хотели сделать это:

CREATE TRIGGER DOW ON Food
FOR INSERT
AS
BEGIN
    SET NOCOUNT ON;
    -- update the day of the week for the inserted rows
    UPDATE Food
        SET [DayOfWeek] = DATENAME(dw, f.[Date])
    FROM Food f
        INNER JOIN inserted i ON f.FoodID = i.FoodID
END
GO
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...