2015-03-20 1 views
0

Я много оборачивался и еще не нашел то, что я ищу. Извините, если это дублированный вопрос, я не видел того, что соответствовало моим потребностям.SQL Trigger для обновления/вставки в logTable на основе обновлений и вставок в ApplicationTable

У меня есть таблица приложений [UserInRoles], которая содержит 2 столбца [UserID] и [RoleID]. Приложение управляет этой таблицей с помощью вложений для новых пользователей и обновлений, когда пользователь переключается на другую роль.

У меня есть история Таблица [UserRoleHistory], который имеет 4 колонки [UserID], [RoleID_New], [RoleID_Old], [DateOfChange]

Что мне нужно, чтобы выяснить, как создать триггер, который будет вставить новую строку в [UserRoleHistory] каждый раз [UserInRoles].[RoleId] изменения. Я хочу, чтобы старый RoleId хранился в столбце [RoleId_Old], а новый RoleId хранился в столбце [RoleId_New]. Также [UserId] необходимо хранить и GETDATE() используется для добавления значения в [DateOfChange]

Кроме того, (это возможно) Я хотел бы на курок, чтобы заметить, когда вставка выполнена в таблице приложения [UserInRoles] и сохранить данные [UserId], [RoleId],GETDATE() в таблицу истории [UserId], [RoleId_New] , GETDATE() и оставьте значение [RoleId_Old] as a null.

Я очень новичок в триггерах и не уверен, как действовать дальше. У меня нет прав на удаление триггера, если я его испортил, поэтому я еще не пытался его создать. Просто хотел сначала получить экспертный ввод. Заранее благодарим всех и всех, кто тратит время на чтение и ответ на этот вопрос.

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

CREATE TRIGGER [dbo].[UserInRoles_Insert_Delete_Update] ON [dbo].[UsersInRoles] 
AFTER INSERT,DELETE,UPDATE 
AS 
    IF (SELECT COUNT(*) FROM inserted) > 0 
     BEGIN 
      IF (SELECT COUNT(*) FROM deleted) > 0 
       BEGIN 
        -- update! 
        INSERT INTO [dbo].[UserRole_History](WinNTLogin,UserID,RoleID_Old,RoleID_New,RoleName,DateOfChange,Operation) 
         SELECT (select distinct[LoweredUserName] from [dbo].[Users] 
           where (inserted.UserId = Users.UserId) or (deleted.UserId = Users.UserId)) 
           ,CASE 
            WHEN inserted.UserID IS NOT NULL THEN inserted.UserID 
            ELSE deleted.UserID 
           END 
           ,deleted.RoleID 
           ,inserted.RoleID 
           ,(select distinct[RoleName] from [dbo].[Roles] 
            where (inserted.RoleId = Roles.RoleId) or (deleted.RoleId = Roles.RoleId)) 
           ,GETDATE() 
           ,'U' 
         FROM inserted 
         FULL JOIN deleted 
         ON inserted.UserID = deleted.UserID 
       END 
      ELSE 
       BEGIN 
        -- insert! 
        INSERT INTO [dbo].[UserRole_History](WinNTLogin,UserID,RoleID_Old,RoleID_New,RoleName,DateOfChange,Operation) 
         SELECT (select distinct[LoweredUserName] from [dbo].[Users] 
           where (inserted.UserId = Users.UserId) or (deleted.UserId = Users.UserId)) 
           ,CASE 
            WHEN inserted.UserID IS NOT NULL THEN inserted.UserID 
            ELSE deleted.UserID 
           END 
           ,deleted.RoleID 
           ,inserted.RoleID 
           ,(select distinct[RoleName] from [dbo].[Roles] 
            where (inserted.RoleId = Roles.RoleId) or (deleted.RoleId = Roles.RoleId)) 
           ,GETDATE() 
           ,'I' 
         FROM inserted 
         FULL JOIN deleted 
         ON inserted.UserID = deleted.UserID 
       END 
     END 
    ELSE 
     BEGIN 
      -- delete! 
      INSERT INTO [dbo].[UserRole_History](WinNTLogin,UserID,RoleID_Old,RoleID_New,RoleName,DateOfChange,Operation) 
         SELECT (select distinct[LoweredUserName] from [dbo].[Users] 
           where (inserted.UserId = Users.UserId) or (deleted.UserId = Users.UserId)) 
           ,CASE 
            WHEN inserted.UserID IS NOT NULL THEN inserted.UserID 
            ELSE deleted.UserID 
           END 
           ,deleted.RoleID 
           ,inserted.RoleID 
           ,(select distinct[RoleName] from [dbo].[Roles] 
            where (inserted.RoleId = Roles.RoleId) or (deleted.RoleId = Roles.RoleId)) 
           ,GETDATE() 
           ,'D' 
         FROM inserted 
         FULL JOIN deleted 
         ON inserted.UserID = deleted.UserID 
     END 
GO 

ответ

1

ПРИМЕЧАНИЕ. Я использовал те же имена таблиц, которые вы сделали, поэтому НЕ запускайте это против своей базы данных с фактическими таблицами, потому что я их удаляю.

Попробуйте это. Это будет работать для любого обновления, вставки или удаления. Если UserID изменен (что, вероятно, не должно произойти), тогда он будет просто выглядеть как новый UserId с новым RoleID. Позвольте мне знать, если вам нужно что-нибудь еще.

--If the tables exist, delete them 
IF OBJECT_ID('UserInRoles') IS NOT NULL 
    DROP TABLE UserInRoles; 
IF OBJECT_ID('UserRoleHistory') IS NOT NULL 
    DROP TABLE UserRoleHistory; 

CREATE TABLE UserInRoles 
(
UserID INT PRIMARY KEY, 
RoleID INT 
); 
GO 

CREATE TABLE UserRoleHistory 
(
UserID INT, 
RoleID_Old INT, 
RoleID_New INT, 
DateOfChange DATETIME 
); 
GO 

CREATE TRIGGER trg_History ON UserInRoles 
AFTER INSERT,DELETE,UPDATE 
AS 
    INSERT INTO UserRoleHistory(UserID,RoleID_Old,RoleID_New,DateOfChange) 
     SELECT CASE 
        WHEN inserted.UserID IS NOT NULL THEN inserted.UserID 
        ELSE deleted.UserID 
       END, 
       deleted.RoleID, 
       inserted.RoleID, 
       GETDATE() 
     FROM inserted 
     FULL JOIN deleted 
     ON inserted.UserID = deleted.UserID 
GO 

INSERT INTO UserInRoles 
VALUES (1,1); 
INSERT INTO UserInRoles 
VALUES (2,1); 
INSERT INTO UserInRoles 
VALUES (3,2); 
GO 

UPDATE UserInRoles 
SET RoleID = 111 
WHERE RoleID = 1; 
GO 

UPDATE UserInRoles 
SET RoleID = 222 
WHERE RoleID = 2; 
GO 

DELETE 
FROM UserInRoles 
WHERE UserID >= 1 
GO 

SELECT * 
FROM UserRoleHistory 
ORDER BY DateOfChange 

Результаты:

UserID  RoleID_Old RoleID_New DateOfChange 
----------- ----------- ----------- ----------------------- 
1   NULL  1   2015-03-20 13:06:37.010 
2   NULL  1   2015-03-20 13:06:37.010 
3   NULL  2   2015-03-20 13:06:37.010 
2   1   111   2015-03-20 13:06:37.047 
1   1   111   2015-03-20 13:06:37.047 
3   2   222   2015-03-20 13:06:37.050 
3   222   NULL  2015-03-20 13:06:37.063 
2   111   NULL  2015-03-20 13:06:37.063 
1

MSDN от создания спускового документации (https://msdn.microsoft.com/en-GB/library/ms189799.aspx) имеет несколько полезных примеров к концу. Я беззастенчиво копировать/вставить первый ниже в качестве примера:

IF OBJECT_ID ('Sales.reminder2','TR') IS NOT NULL 
DROP TRIGGER Sales.reminder2; 
GO 
CREATE TRIGGER reminder2 
ON Sales.Customer 
AFTER INSERT, UPDATE, DELETE 
AS 
    EXEC msdb.dbo.sp_send_dbmail 
    @profile_name = 'AdventureWorks2012 Administrator', 
    @recipients = '[email protected]', 
    @body = 'Don''t forget to print a report for the sales force.', 
    @subject = 'Reminder'; 
GO 

Это имеет отношение к вам, потому что он показывает

  1. Как огонь триггер после транзакции произошла (в частности, один whic должен был привести к изменению - подробнее об этом позже)
  2. Как отключить свой собственный sql впоследствии. В вашем случае это будет вставлять в другую таблицу, а не отправлять электронное письмо.
  3. Показывает, как сбросить/воссоздать триггер, если он уже существует (для целей тестирования - при условии, что вы тестируете это первым, не применяя прямо к жизни).

Если вам нужно специально сравнить значение, чтобы убедиться, что значение изменилось, то есть предыдущий пост на что-то подобное here.Essentialy вы пишете

INSTEAD OF INSERT 

в месте

AFTER INSERT 

, то вы можете сделать какие-либо условные логические или CRUD операции по мере необходимости.

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