我有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表。
这样做的最佳方式是什么?
答案 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