如何在SQL Server中更新两个具有引用表的表?

时间:2009-07-16 14:15:02

标签: sql sql-server tsql

我有3张桌子。

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

2. UsersGroups 2 Cols
UserID - GroupID

3. Groups 3 Cols
GroupID - GroupName - Flags

我想要做的是选择一个特定的UserName即USERA并更新Flags列。 但我还想将Groups表中的Flags列更新为相同的值。

我在2个表之间唯一的连接是UsersGroups表。

这样做的最佳方式是什么?

5 个答案:

答案 0 :(得分:2)

这应该这样做:

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;

编辑:更正了第二个查询中的错误。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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'

答案 3 :(得分:0)

关于选择特定用户,请使用以下内容:

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>)

希望这些有用

答案 4 :(得分:0)

这应该是维持数据完整性的原子工作单元!更新多个表时,必须保持同步使用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事务块中的代码是从Chris的回答中公然复制/粘贴的。

修改

有很多关于模糊列名的评论,但这里的TSQL没有任何问题。这是我在MSSMS中测试的整个DML和QUERY:

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