我有两个传说配方和参数。配方表包含具有相同配方名称的多个版本。参数表包含一个配方的多个参数名称。如何按配方名称和参数名称将constantguid更新为相同的配方和相同的参数组?
CREATE TABLE [dbo].[Recipe](
[VersionGUID] [varchar](36) NULL,
[Name] [nvarchar](50) NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Parameter](
[ParameterGUID] [varchar](36) NULL,
[VersionGUID] [varchar](36) NULL,
[ParameterName] [nvarchar](50) NULL,
[ConstantGUID] [varchar](50) NULL
) ON [PRIMARY]
GO
-- Add 5 rows to [dbo].[Parameter]
INSERT INTO [dbo].[Parameter] ([ParameterGUID], [VersionGUID], [ParameterName], [ConstantGUID]) VALUES ('1B00E5ED-25A5-4FEA-AE73-14CDC7871951', 'AB00E5ED-25A5-4FEA-AE73-14CDC787195A', N'Parameter1', '26976642-12B6-462A-982B-74448DDA33B6')
INSERT INTO [dbo].[Parameter] ([ParameterGUID], [VersionGUID], [ParameterName], [ConstantGUID]) VALUES ('5AD70E77-E377-4661-A525-6711A1992217', '8B00E5ED-25A5-4FEA-AE73-14CDC7871953', N'Parameter1', '55D724C5-51A6-48B7-9161-2364F004BB7F')
INSERT INTO [dbo].[Parameter] ([ParameterGUID], [VersionGUID], [ParameterName], [ConstantGUID]) VALUES ('A0142B6A-52F6-4A49-ADBA-DC5D4C2BEF7A', '20142B6A-52F6-4A49-ADBA-DC5D4C2BEF71', N'Parameter2', 'B5903A3D-B606-49DD-A75C-A1B29740EBEB')
INSERT INTO [dbo].[Parameter] ([ParameterGUID], [VersionGUID], [ParameterName], [ConstantGUID]) VALUES ('A96113F9-1046-4E35-B320-BE3126D522CF', '20142B6A-52F6-4A49-ADBA-DC5D4C2BEF71', N'Parameter1', '108197E8-47CA-477C-B97F-4BF0321C1D91')
INSERT INTO [dbo].[Parameter] ([ParameterGUID], [VersionGUID], [ParameterName], [ConstantGUID]) VALUES ('AB00E5ED-25A5-4FEA-AE73-14CDC787195A', '8B00E5ED-25A5-4FEA-AE73-14CDC7871953', N'Parameter2', 'B3AC6268-6257-4E3B-B0C9-4418E4A09E40')
-- Add 3 rows to [dbo].[Recipe] with non-unique comparison key
SET ROWCOUNT 1
INSERT INTO [dbo].[Recipe] ([VersionGUID], [Name]) VALUES ('20142B6A-52F6-4A49-ADBA-DC5D4C2BEF71', N'Recipe1')
INSERT INTO [dbo].[Recipe] ([VersionGUID], [Name]) VALUES ('8B00E5ED-25A5-4FEA-AE73-14CDC7871953', N'Recipe1')
INSERT INTO [dbo].[Recipe] ([VersionGUID], [Name]) VALUES ('AB00E5ED-25A5-4FEA-AE73-14CDC787195A', N'Recipe2')
SET ROWCOUNT 0
如果您运行以下查询,我希望108197E8-47CA-477C-B97F-4BF0321C1D91
和55D724C5-51A6-48B7-9161-2364F004BB7F
相同。 B3AC6268-6257-4E3B-B0C9-4418E4A09E40
和B5903A3D-B606-49DD-A75C-A1B29740EBEB
相同,等等。我有5密耳的记录要更新。
select name+parametername as name_parametername,name as RecipeName,parametername,constantguid,Parameter.parameterguid
from dbo.Recipe,dbo.Parameter
where dbo.Recipe.versionguid=dbo.Parameter.versionguid
order by name_parametername
提前致谢。
答案 0 :(得分:0)
注1:在更新生产数据库之前,请进行备份。恢复此备份并进行一些测试,首先是几行,然后是更多行。
注意2:检查是否有足够的可用空间用于数据库日志文件。
注意3:如果取消注释EXEC sp_trace_generateevent
行,然后创建跟踪以捕获UserConfigurable0
事件,您可以看到使用新ID GUID更新了多少行(服务器跟踪的开销比SQL Profiler少)迹线)。
注4:每次只执行一步。
注意5:在更新生产数据库之前,请进行另一次备份。本说明是故意重复的。
-- dbo.NewGUIDs is used to generate the new ConstantGUIDs
-- AnotherDB.dbo.NewGUIDs: this table could be created in another DB to minimize DB log increase for current DB
-- Note: This script assumes that Parameter.ParameterGUID column has an unique index (ex. is PRIMARY KEY or UNIQUE [KEY])
-- Step 1: It creates the NewGUIDs table, it insert current ParameterGUID guids and
-- it generates some kind of group ID (column Rnk) for every (Receipt.Name and Parameter.ParameterName) pair
/*
CREATE AnotherDB;
GO
USE AnotherDB;
GO
*/
CREATE TABLE /*AnotherDB.*/dbo.NewGUIDs(
ParameterGUID UNIQUEIDENTIFIER PRIMARY KEY,
Rnk INT NOT NULL,
NewConstantGUID UNIQUEIDENTIFIER NULL
);
INSERT INTO /*AnotherDB.*/dbo.NewGUIDs(ParameterGUID,Rnk) -- Ar INSERT INTO AnotherDB.dbo.NewGUIDs
SELECT p.ParameterGUID,
-- r.Name,p.ParameterName,
DENSE_RANK() OVER(ORDER BY r.Name,p.ParameterName) AS Rnk
FROM dbo.Recipe r JOIN dbo.Parameter p ON r.VersionGUID=p.VersionGUID;
GO
-- This index is useful for the next queries
CREATE INDEX IN_NewGUIDs_Rnk
ON /*AnotherDB.*/dbo.NewGUIDs(Rnk);
GO
-- End of Step 1
-- Step 2: It generates the new GUIDs for ConstantGUID column
DECLARE @GUIDs TABLE(
Rnk INT PRIMARY KEY,
NewGUID UNIQUEIDENTIFIER DEFAULT NEWSEQUENTIALID() -- or NEWID()
);
INSERT @GUIDs(Rnk)
SELECT Rnk
FROM (SELECT DISTINCT Rnk FROM /*AnotherDB.*/dbo.NewGUIDs)a;
UPDATE x
SET NewConstantGUID=y.NewGUID
FROM /*AnotherDB.*/dbo.NewGUIDs x
INNER JOIN @GUIDs y ON x.Rnk=y.Rnk;
-- Check: this query should return 0 rows
SELECT * FROM dbo.NewGUIDs n WHERE NewConstantGUID IS NULL;
GO
-- End of Step 2
-- Step 3: It adds a new column (IsUpdated) to dbo.Parameter.
-- This column will be updated (SET IsUpdated=1) when ConstantGUID is updated with the new value
ALTER TABLE dbo.Parameter
ADD IsUpdated BIT NULL;
GO
CREATE INDEX IN_Parameter_IsUpdated
ON dbo.Parameter(IsUpdated);
GO
-- End of Step 3
-- Step 4 (final step): It updates ConstantGUID with new values from /*AnotherDB.*/dbo.NewGUIDs
SET XACT_ABORT ON;
DECLARE @AffectedRowsCount INT,
@TotalAffectedRowsCount INT,
@EventClass INT,
@UserInfo NVARCHAR(128);
SELECT @EventClass=82,
@AffectedRowsCount=0,
@TotalAffectedRowsCount=0;
WHILE 1=1
BEGIN
BEGIN TRANSACTION;
UPDATE TOP(4000) p -- TOP(4000) to prevent lock escalation; See http://msdn.microsoft.com/en-us/library/ms184286(v=sql.105).aspx
SET ConstantGUID=n.NewConstantGUID,
IsUpdated=1 -- It marks current so I know that it was updated and I don't have to update the same row again
FROM dbo.Parameter p INNER JOIN /*AnotherDB.*/dbo.NewGUIDs n ON p.ParameterGUID=n.ParameterGUID
WHERE p.IsUpdated IS NULL -- Wasn't updated
SET @AffectedRowsCount=@@ROWCOUNT;
SET @TotalAffectedRowsCount=@TotalAffectedRowsCount+@AffectedRowsCount;
IF @AffectedRowsCount=0
BEGIN
SET @UserInfo='Finish! > '+CONVERT(VARCHAR(11),@TotalAffectedRowsCount);
-- EXEC sp_trace_generateevent @EventClass,@UserInfo;
BREAK;
END
ELSE
BEGIN
SET @UserInfo='Processing > '+CONVERT(VARCHAR(11),@TotalAffectedRowsCount);
-- It generates a custom event (82). You may use SQL Profiler to catch this event (UserConfigurable0)
-- EXEC sp_trace_generateevent @EventClass,@UserInfo;
END
COMMIT;
END;
GO
-- End of Step 4
-- Cleanup
/*
ALTER TABLE dbo.Parameter
DROP COLUMN IsUpdated;
GO
DROP INDEX IN_Parameter_IsUpdated
ON dbo.Parameter
DROP TABLE /*AnotherDB.*/dbo.NewGUIDs
-- DROP DATABASE AnotherDB
*/
答案 1 :(得分:0)
谢谢波格丹。你是一个很好的帮助。
我在他现有的Parameter表中添加了一个UniqueRcipeParameterName。由于配方名称和参数名称的组合在所有版本中都是相同的。
PRINT N'Updating Recipe Parameters ConstantGUID...'
ALTER TABLE Parameter
ADD UniqueRecipeParameter NVARCHAR(600) NULL;
GO
ALTER TABLE Parameter
ADD IsPhase bit NULL ;
GO
UPDATE Parameters
SET UniqueRecipeParameter = Recipe.Name + '-' + Parameter.Name,
IsPhase = 0
FROM Recipe,
Parameter
WHERE Recipe.VersionGUID = Parameter.VersionGUID
DECLARE @GUIDs TABLE
(
--Assuming Recipe Name and Parameter Name will not exit 450 characters. The maximum key length is 900 bytes which is 450
UniqueRecipeParameter NVARCHAR(450) PRIMARY KEY ,
NewGUID UNIQUEIDENTIFIER DEFAULT NEWID()
) ;
INSERT @GUIDs
( UniqueRecipeParameter
)
SELECT UniqueRecipeParameter
FROM ( SELECT DISTINCT
UniqueRecipeParameter
FROM Parameter
WHERE Parameter.IsPhase = 0
) a ;
UPDATE x
SET ConstantGUID = y.NewGUID
FROM dbo.Parameter x
INNER JOIN @GUIDs y ON x.UniqueRecipeParameter = y.UniqueRecipeParameter ;
PRINT N'Cleaning up...'
ALTER TABLE Parameter
DROP COLUMN UniqueRecipeParameter;
GO
ALTER TABLE Parameter
DROP COLUMN IsPhase;
GO
由于它是离线升级,我可以跳过3和4。
再次感谢。它工作。