這應該確實是保持數據完整性的原子單位!當更新多個表,他們必須保持同步使用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的事務塊裏面的代碼是公然複製/克里斯的回答貼上。
編輯
有很多的關於不明確的列名的意見,但沒有什麼錯在這裏TSQL這是一個完整的DML和查詢我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
內連接將花費更多的時間,它會影響應用程序和查詢 – Ahmy 2009-07-16 14:31:41
如果表索引適當,不應顯著的運行時間。 – 2009-07-16 14:34:35
沒有人提及他們解決方案中數據完整性的危險,要小心。 – 2009-07-16 14:35:35