Quantcast
Channel: CodeSection,代码区,SQL Server(mssql)数据库 技术分享 - CodeSec
Viewing all articles
Browse latest Browse all 3160

SQL Server update group by multiple table names?

$
0
0

I have two tales Recipe and Parameter. Recipes table contains multiple versions with the same recipe name. Parameter table contains multiple parameter names for one recipe. How can I update a constantguid to the same recipe and same parameter group by recipe name and parameter name?

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

If you run the following query, I want 108197E8-47CA-477C-B97F-4BF0321C1D91 and 55D724C5-51A6-48B7-9161-2364F004BB7F be the same. B3AC6268-6257-4E3B-B0C9-4418E4A09E40 and B5903A3D-B606-49DD-A75C-A1B29740EBEB be the same and so forth. I have 5 mil records to update.

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

Thanks in advance.

Note 1: Before updating the production database take a backup. Restore this backup and do some tests, first with few rows and then with more rows.

Note 2: Check if you have enough free space for database log files.

Note 3: You could see how many rows were updated with new id GUIDs if you uncomment EXEC sp_trace_generateevent lines and then create a trace to catch UserConfigurable0 event (server traces have a less overhead than SQL Profiler traces).

Note 4: Execute just one step at time.

Note 5: Before updating the production database take another backup. This note is intentionally duplicated.

-- 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 @<a href="/cdn-cgi/l/email-protection" data-cfemail="307156565553445554625f4743735f455e440d70">[email protected]</a>@ROWCOUNT; SET @<a href="/cdn-cgi/l/email-protection" data-cfemail="affbc0dbcec3eec9c9caccdbcacbfdc0d8dcecc0dac1db92effbc0dbcec3eec9c9caccdbcacbfdc0d8dcecc0dac1db">[email protected]</a><a href="/cdn-cgi/l/email-protection" data-cfemail="193259587f7f7c7a6d7c7d4b766e6a5a766c776d">[email protected]</a>; 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 */

Viewing all articles
Browse latest Browse all 3160

Trending Articles