Как обновить две таблицы, которые имеют справочную таблицу в SQL Server? - PullRequest
0 голосов
/ 16 июля 2009

У меня 3 таблицы.

1. Users 4 Cols
UserID - UserName - RealName - Flags

2. UsersGroups 2 Cols
UserID - GroupID

3. Groups 3 Cols
GroupID - GroupName - Flags

Что я хочу сделать, это выбрать конкретное имя пользователя, например, USERA, и обновить столбец Flags. но я также хочу обновить столбец Flags в таблице Groups до того же значения.

Единственное соединение между двумя таблицами, которое у меня есть, - это таблица UsersGroups.

Каков наилучший способ сделать это?

Ответы [ 5 ]

2 голосов
/ 16 июля 2009

Это должно сделать это:

Create Proc spUpdateUsersFlag(@UserName as Varchar(32), @Flags as int)
 AS
Declare @UserID as int

BEGIN Transaction
BEGIN TRY
    SELECT @UserID = UserID 
        From Users 
        Where UserName = @UserName
    UPDATE Users
        SET Flags = @Flags
        WHERE UserID = @UserID
    UPDATE Groups
        SET Flags = @Flags
        FROM Groups G INNER JOIN UserGroups UG ON G.GroupId = UG.GroupID
        WHERE UG.UserID = @UserID
END TRY
BEGIN CATCH
    DECLARE @ErrorMessage NVARCHAR(4000), @ErrorSeverity INT
    -- Assign variables to error-handling functions that 
    -- capture information for RAISERROR.
    SELECT @ErrorMessage = ERROR_MESSAGE(), @ErrorSeverity = ERROR_SEVERITY()
    -- Rollback the failed transaction
    ROLLBACK;
    -- Raise an error: with the original error information.
    RAISERROR(@ErrorMessage, @ErrorSeverity, 1);
END CATCH
COMMIT Transaction;

EDIT: исправлена ​​ошибка во втором запросе.

0 голосов
/ 16 июля 2009

Это действительно должна быть атомная единица работы для поддержания целостности ваших данных !!! При обновлении нескольких таблиц, которые должны быть синхронизированы, используйте BEGIN и COMMIT / ROLLBACK TRAN или, если у вас Sql Server 2008, используйте новый синтаксис TRY CATCH

BEGIN TRAN
    BEGIN TRY
    UPDATE dbo.Users
    SET Flags = @var
    WHERE UserName = 'UserA'

    UPDATE dbo.Groups
    SET Flags = @var
    FROM dbo.Users u INNER JOIN dbo.UsersGroups ug ON u.UserID = ug.UserID
        INNER JOIN dbo.Groups g ON g.GroupID = ug.GroupID
    WHERE u.UserName = 'UserA'
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
    ROLLBACK TRANSACTION;

END CATCH
IF @@TRANCOUNT > 0
    COMMIT TRAN

Кроме того, если ваши данные денормализованы для повышения производительности, то это ваше лучшее решение. Если это не так, я рекомендую вам отказаться от одного из столбцов. (Ждет типичного "Это не моя схема, я унаследовал это .. наследие бла ... хе хе:))

PS код внутри блока транзакции вопиющим образом копируется / вставляется из ответа Криса.

EDIT

Есть много комментариев по поводу неоднозначных имен столбцов, но здесь нет ничего плохого в TSQL. Вот полный DML и QUERY, которые я протестировал в MSSMS:

IF NOT EXISTS (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE 

TABLE_NAME='Users')
BEGIN
    CREATE TABLE Users
    (
        UserID      INT IDENTITY(1,1) PRIMARY KEY,
        UserName    NVARCHAR(32) NOT NULL,
        RealName    NVARCHAR(64) NOT NULL,
        Flags       NVARCHAR(16) NOT NULL
    )
END
GO

IF NOT EXISTS (SELECT ix.name FROM sys.indexes ix WHERE ix.name='IX_Users_UserName')
BEGIN
    CREATE UNIQUE INDEX IX_Users_UserName ON Users(UserName)
END
GO

IF NOT EXISTS (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='Groups')
BEGIN
    CREATE TABLE Groups
    (
        GroupID     INT IDENTITY(1,1) PRIMARY KEY,
        GroupName   NVARCHAR(32) NOT NULL,
        Flags       NVARCHAR(16) NOT NULL
    )
END
GO

IF NOT EXISTS (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='UsersGroups')
BEGIN
    CREATE TABLE UsersGroups
    (
        UserID  INT NOT NULL,
        GroupID INT NOT NULL,
        CONSTRAINT PK_UsersGroups PRIMARY KEY CLUSTERED (UserID, GroupID),
        CONSTRAINT FK_UsersGroups_UserID FOREIGN KEY (UserID) REFERENCES Users(UserID),
        CONSTRAINT FK_UsersGroups_GroupID FOREIGN KEY (GroupID) REFERENCES Groups(GroupID),
    )
END
GO

DECLARE @count INT = (SELECT COUNT(*) FROM Users)
IF @count = 0
BEGIN
    INSERT INTO Users(UserName, RealName, Flags)
    SELECT 'USERA', 'User A', 'Flags A'
    UNION ALL
    SELECT 'USERB', 'User B', 'Flags B'
END

SELECT @count = (SELECT COUNT(*) FROM Groups)
IF @count = 0
BEGIN
    INSERT INTO Groups(GroupName, Flags)
    SELECT 'Group A', 'Flags A'
    UNION ALL
    SELECT 'Group B', 'Flags B'
END

SELECT @count = (SELECT COUNT(*) FROM UsersGroups)
IF @count = 0
BEGIN
    INSERT INTO UsersGroups(GroupID, UserID)
    SELECT 1, 1
    UNION ALL
    SELECT 2, 2
END
GO

BEGIN TRAN
    BEGIN TRY
        DECLARE @var NVARCHAR(16)
        SET @var = 'New Flags A'

        UPDATE dbo.Users
        SET Flags = @var
        WHERE UserName = 'UserA'

        UPDATE dbo.Groups
        SET Flags = @var
        FROM dbo.Users u INNER JOIN dbo.UsersGroups ug ON u.UserID = ug.UserID
            INNER JOIN dbo.Groups g ON g.GroupID = ug.GroupID
        WHERE u.UserName = 'UserA'

    END TRY
    BEGIN CATCH

        IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;

    END CATCH

IF @@TRANCOUNT > 0
    COMMIT TRAN

SELECT Flags FROM Users

SELECT Flags FROM Groups
0 голосов
/ 16 июля 2009
UPDATE dbo.Users
SET Flags = @var
WHERE UserName = 'UserA'

UPDATE g
SET g.Flags = @var
FROM dbo.Users u INNER JOIN dbo.UsersGroups ug ON u.UserID = ug.UserID
INNER JOIN dbo.Groups g ON g.GroupID = ug.GroupID
WHERE u.UserName = 'UserA'
0 голосов
/ 16 июля 2009

Для выбора конкретного пользователя используйте следующее:

select UserName from Users where UserID = <USERA>

И обновляя столбец флага в обеих таблицах: пользователи и группы делают следующее:

update Users set Flags = <Your Flag> where UserID = <USERA>
update Groups set Flags = <Your Flag> where GroupID in (select GroupID from UsersGroups where UserID = <USERA>)

Надеюсь, что это полезно

0 голосов
/ 16 июля 2009

Оператор UPDATE может обновлять только записи одной таблицы.

UPDATE Users SET Flags = @Flags WHERE UserID = @UserID

UPDATE Groups SET Flags = @Flags
FROM Groups
INNER JOIN UsersGroups ON UsersGroups.GroupID = Groups.GroupID
WHERE UsersGroups.UserID = @UserID
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...