Tuesday 15 October 2019

Ways of importing excel data into SQL Server Table

There are a couple of ways to import excel data into SQL Server. One of the most popular ways is to use SSIS to import the data into SQL Server from Excel workbooks. Another one is to use OPENROWSET and linked servers. We will take one scenario and implement both the ways.

Scenario: 

I have 'n' number of excel workbooks (all of them have the same schema) in a network drive. I will have to process each excel file into one common SQL table and move the processed file into "ProcessedFiles" folder.



So, SSIS or OPENROWSET approach had to do below steps.
1. Read the network path
2. Loop through each file, process and move the processed file into "ProcessedFiles" folder.

I have added the following 2 columns (Id, Name) and added 4 rows of dummy data in the excel.  I have copied the same excel 4 times and changed the name "Excel Data 10*.xls". I have created a table with the same schema in the SQL Server using the below script.
CREATE TABLE exceldata( id INTNAME sysname) 

Let's do the demo.

SSIS Approach:

Since we have to read each file in the network drive, I am using "Foreach Loop Container" to loop through each file and process. I have chosen "Enumerator" as "Foreach File Enumerator" like below screenshot, Please update "Folder:" and "Files:" correctly as highlighted.  Note that I am retrieving "Fully qualified" file path from here and going to assign it to a variable to use it in "Excel File Path" in excel source.

Go to "Variable Mappings" and create a new variable named "Filepath" to store Fully qualified file Path for each iteration. I have assigned design value for the variable "Filepath" as "C:\NARA\Excel Data 101.xls".

Let's add a data flow task from SSIS Toolbox into the "Foreach Loop Container".

Go into the data flow task and add "Excel Source". Configure excel source by adding "Excel Connection Manager".

Right-click on "Excel Connection Manager", click on properties, set the "Delay Validation" to "True". Click on "Expression", Select "Property" as "ExcelFIlePath" and Click "..." right to the expression and drag "User::FilePath" and drop to the "Expression: "and click on "Evaluated value" to check. Click on "OK"

Add "OLEDB Destination" and configure it appropriately with the right table.

It is like below in the data flow task. Ignore the "Truncation" warning.

Please now come back to control flow, add a new variable to store the "ProcessedFiles" network drive path and add "File System Task" to move the processed file to the "ProcessedFiles" Folder.  Please update the settings of "File System Task" like below and clik "OK".

Now everything is done. Execute the SSIS package and check the "ProcessedFiles" folder.


Check the SQL Table data.

OPENROWSET Approach: 

Let's truncate "exceldata" table in MyDB to use OPENROWSET approach.
TRUNCATE TABLE exceldata 
I have moved the ProcessedFiles again back to the c:\NARA folder to process files again using OPENROWSET approach.

In order to use "OPENROWSET" approach, we will have to install "Microsoft.ACE.OLEDB.12.0 for Windows" in the server. An installer can be found here for 64 bt version. Get the appropriate installer from the Microsoft site and install it. Please make sure to register the "msexcl40.dll" using below command prompt.
> C:\Windows\SysWOW64\regsvr32 C:\Windows\SysWOW64\msexcl40.dll

Reconfigure xp_cmdshell, 'Ad Hoc Distributed Queries' and 'Microsoft.ACE.OLEDB.12.0' using below script.
USE mydb 
go 
EXEC Sp_configure  'xp_cmdshell',1 
go 
RECONFIGURE 
go 
Sp_configure 'show advanced options', 1; 
go 
RECONFIGURE; 
go 
Sp_configure 'Ad Hoc Distributed Queries', 1; 
go 
RECONFIGURE; 
go 
EXEC Sp_msset_oledb_prop N'Microsoft.ACE.OLEDB.12.0', N'AllowInProcess',1 
go 
EXEC Sp_msset_oledb_prop N'Microsoft.ACE.OLEDB.12.0', N'DynamicParameters', 1 
go 

Use below script to load the data from excel workbooks into SQL Table and move the processed files to "ProcessedFiles" folder. Update the appropriate values in the highlighted before running the script. You can use this script in a SQL stored procedure and call sproc using SQL agent job to run based on the schedule (daily/weekly/monthly).
USE MyDB
GO
IF(OBJECT_ID('tempdb..#DirectoryTree_F') IS NOT NULL ) DROP TABLE #DirectoryTree_F
CREATE TABLE #DirectoryTree_F  (id int IDENTITY(1,1) ,subdirectory nvarchar(512),depth int,isfile bit);
DECLARE @FolderPath SYSNAME = 'C:\NARA\'
DECLARE @ProcessedFolderPath SYSNAME = 'C:\NARA\ProcessedFiles\'
INSERT #DirectoryTree_F (subdirectory,depth,isfile)
EXEC master.sys.xp_dirtree @FolderPath,1,1;
DELETE #DirectoryTree_F WHERE subdirectory NOT like 'Excel Data%.xls'
--SELECT * FROM #DirectoryTree_F
WHILE EXISTS (SELECT * FROM #DirectoryTree_F)
BEGIN
  DECLARE @FileName SYSNAME,@FilePath NVARCHAR(3000),@SQL NVARCHAR(4000),@OpenRowSQL NVARCHAR(4000)
  SELECT TOP 1  @FileName = subdirectory FROM #DirectoryTree_F
  SELECT @FilePath = @FolderPath + @FileName
  SET @OpenRowSQL =  'INSERT exceldata (Id,[Name]) SELECT Id,[Name] FROM OPENROWSET(''Microsoft.ACE.OLEDB.12.0'',''Excel 12.0; Database='+@FilePath+''', [Sheet1$]);'
  --PRINT @OpenRowSQL
  EXEC SP_EXECUTESQL @OpenRowSQL
  SET @SQL = 'MOVE "' + @FilePath + '" "' +  @ProcessedFolderPath+'" '
  EXEC xp_cmdshell @SQL
  --PRINT @SQL
  DELETE #DirectoryTree_F WHERE subdirectory = @FileName
END
GO

Let's check the data in the table.
We have loaded all the data from excel sheet(s) into SQL Server Table and moved the processed files to the different folder using OPENROWSET approach.
Which approach do you think is better and effective?

Please remember that Microsoft has left the following note in their online docs about "OPENROWSET" approach. 

"The ACE provider (formerly the Jet provider) that connects to Excel data sources is intended for interactive client-side use. If you use the ACE provider on SQL Server, especially in automated processes or processes running in parallel, you may see unexpected results."

Please choose the approach carefully based on your requirement. Thanks

Thursday 3 October 2019

Challenges in creating Tabular Report in Tableau Using Table Calculations

SCENARIO:

We have one tableau model, which extracts patron rating data at a day level.

Tableau model has below columns only.
GAME_DAY, PATRON_NO, BET, WIN

One of our users tried to create this report using Tableau by keeping below conditions in mind.

  1. Tableau workbook has to look for the gaming days that are consecutive for a patron number and count that as one "Trip".
  2. Tableau workbook should be having a "Recent trip" filter to filter the records based on Recent Trip Number.  

Patron_no Trip Start Date Trip End Date Recent Trip? BET WIN
~~~~~ 1/9/2019 1/9/2019 4 $             58   $           100 
13/09/2019 14/09/2019 3 $           439   $           119 
23/09/2019 28/09/2019 2 $        1,278  $        1,931 
30/09/2019 2/10/2019 1 $          950  -$          856 
Sub Total $          2725  $         1294 


When any developer gets this kind of request from the user(s), the developer usually says that Tableau is meant to create visualisation charts/dashboards but not to create TABULAR reports.
But sometimes we can't deny the user request mostly because of the following reason(s).
1. If the report is compliance or regulatory report that customer has to submit every quarter to government bodies. Customer may not be interested to buy/use some other reporting tool just to create/view this kind of reports in another reporting platform like SSRS.
2. Developer wanted to make the user happy by getting the report done in Tableau instead of advising them that it may not be possible in Tableau.
3. The manager wanted to bill 😊 the customer (or user) by developing this kind of reports in Tableau with modifying the tableau model query as an enhancement.

I hear many times when the developer saying that he/she can develop this kind of report in very less time in SSRS or in another reporting tool (whichever tool he/she is expertise).

I have tried to develop this report in Tableau using Tableau Public to showcase that we can develop this kind of report in Tableau too. I managed to get it done to some extent.

I have followed the below approach to achieve this scenario.

1.  I have created a calculated field to get "Trip Start Date". Challenge#1 - This would expect Game_Day column must be added to the Rows to get the correct "Trip Start Date"
RUNNING_MAX(IF Ifnull((( MAX( [game day])) - (LOOKUP(MAX([game day]),-1))),0) <> 1 then 
max([Game Day]) 
END 
)
Please make sure to "Edit Table Calculation" of "Trip Start Date" to below























2. To create "Trip End Date" date for each trip, Challenge#2-  I ended up creating many calculated fields, which would navigate to previous game day and to check whether the patron has visited the venue and it would navigate to 4 previous days as I have created only 4 calculated columns. I know this is NOT the correct approach, there must be some easy approach that I am not aware of.
I have created below calculated fields in order to get "Trip End Date"
[No Of Days] = ( MAX( [Game Day])) -(LOOKUP(MAX([Game Day]), 1)) 
[TE1] =IF [NO OF DAYS] <> -1 last() = 0 MAX([Game Day]) END 
[TE2] =IF NOT isnull([TE1]) THEN [TE1] ELSE ([TE1], 1)) END 
[TE3] =IF NOT Isnull([TE1]) 
then [TE1] elseif NOT isnull([TE2]) THEN [TE2] ELSE (lookup([TE2], 1)) END 
[TE4] = IF NOT Isnull([TE1]) 
then [TE1] elseif NOT isnull([TE2]) THEN [TE2] elseif NOT isnull([TE3]) THEN [TE3] ELSE (lookup([TE3], 1)) END 

[Trip End Date] = [TE4]
Please make sure to "Edit Table Calculation" of  all above calculated fields to below


























3. I have created a calculated field to get Recent Trip NumberTrip End 
[Recent Trip?]
'TRIP ' + STR (
WINDOW_SUM(
IF  ATTR([Game Day]) = (RUNNING_MAX(IF  IFNULL((( max( [Game Day])) - (LOOKUP(max([Game Day]),-1))),0) <> 1 
THEN MAX([Game Day]) END)) 
 THEN 1 ELSE 0 END ) -
RUNNING_SUM(
IF  ATTR([Game Day]) = (RUNNING_MAX(IF  IFNULL((( max( [Game Day])) - (LOOKUP(max([Game Day]),-1))),0) <> 1 
THEN MAX([Game Day]) END)) 
 THEN 1 ELSE 0 END ) + 1
)
Please make sure to "Edit Table Calculation" of  "[Recent Trip?]" also like previous screenshots.

I expect to see highlighted rows as one row but since I cannot remove [Game Day] field from "Rows", I get detailed rows. Is there any way to get summarized row?






















Below are challenges I have faced, couldn't figure out how to resolve in Tableau. 

Challenge#1 -  Since all calculated fields created on [Game Day],  Tableau expected to use [Game Day] in Rows and not merging the records based on other column values. Any Trick here?

















Challenge#2 -  To get the Trip End date correctly, Is there any easy way to get it correct without creating many calculated fields.

Challenge#3 -  Subtotals of discrete measure are not supported. Disabling subtotals on "Trip End Date".





















Below is the sample workbook published in the Tableau-public. Kindly let me know in case if anybody faced and resolved these challenges at the Tableau Desktop level without adding a key column (that distinguishes previous and current trip) in the underlying tableau model. 

Thank you,
Narasimha

Tuesday 1 October 2019

Consolidating DATABASES without impacting its Applications, Reports and Users.


SCENARIO:
One of our SQL enterprise servers has got 150+ game databases, eventually, the team has created a separate database (with exactly the same schema) for each game. Over time, the team end up having 150+ databases and the number is increasing for each month or quarter (at least one game arrives for each quarter that means ONE new DB arrives for each quarter).  The team does not want to make any changes from the application side since many applications and reports are talking to this enterprise server, and, it is a huge effort to change the architecture.
So, I have done a kind of proof concept for them in my previous post for this scenario by keeping below points in mind.
  • Users or reports or applications talking with this enterprise server must NOT having any impact.
  • Inserts must happen against the RESPECTIVE Game database records.
  • The update statements come from applications or users or reports MUST happen AS-IS without any impact.
  • Way of accessing the data from applications or users or reports MUST work AS-IS without any impact.
Team has gone through my previous post, come back and told to post a detailed article having a primary key, unique keys and Foreign Keys in my test tables in each test game databases, and they ought to move few COLD databases data into COMMON_GAME database, keeping HOT databases data AS-IS in the individual game databases. They are NOT ready to move to CLOUD from ON-PREM (though they are using SQL 2016 Ent Version) because of many reasons to implement SQL Server Stretch Database concept(to dynamically stretch warm and cold transactional data).

My thought process is to follow the below steps to showcase that it can be achieved
  1. Create test Game databases with test tables with Primary, unique keys and Foreign Keys and load sample data in test game databases.
    • Create a sample game database 
    • Create sample tables with Primary keys, Foreign keys and Indexes
    • Load the sample data into the sample tables.
    • Clone one more game database with the same schema, RESEED the identity and load the data.
  2. Clone COMMON_GAME database from one of the sample game database.
  3. ADD GAME_NO column (to distinguish each database records) in all tables of COMMON_GAME database.
  4. Update the Primary key constraints in COMMON_GAME database except for Identity Keys.
  5. Update the Foreign key constraints in COMMON_GAME database.
  6. Update the Indexes in COMMON_GAME database.
  7. [Optional Step] Create Partition Schema and Partition Function on GAME_NO
  8. Load the data into COMMON_GAME database from all individual GAME_*** databases and rename the tables (*_Old) after loading the data.
  9. Verify the data in COMMON_GAME database and drop the *_Old tables from individual game databases.
  10. Create views and triggers in all the individual game databases.
  11.  Validate the INSERT and UPDATE statements.
  12.  Maintenance GOING FORWARD when the game database becomes COLD and ready to move to COMMON_GAME database.

Let's the do the DEMO

  1. Create test Game databases with test tables with Primary, unique keys and Foreign Keys and load sample data in test game databases.
Create a sample game database 
USE [master] 
GO 
SET NOCOUNT ON 
GO 
IF EXISTS (SELECT * FROM SYS.sysdatabases WHERE name = 'GAME_001') 
ALTER DATABASE Game_001 SET  SINGLE_USER WITH ROLLBACK IMMEDIATE 
GO 
DROP DATABASE IF EXISTS Game_001 
GO 
CREATE DATABASE Game_001 
GO


















Create sample tables with Primary keys, Foreign keys and Indexes. I have added default constraints for most of the columns just to make life easier.

USE Game_001
GO
 --Drop tables

DROP TABLE  IF EXISTS  [dbo].[Books]
DROP TABLE  IF EXISTS  [dbo].[USERS]
CREATE TABLE [dbo].[USERS](
  [UserID] [bigint] NOT NULL IDENTITY(1,1) ,
  [NationalNo] BIGINT NOT NULL,
  [OwnerId] BIGINT NOT NULL,
  [NAME] [nvarchar](50) NOT NULL,
  [ActiveFlag] bit NOT NULL CONSTRAINT [DF_USERS_ActiveFlag]  DEFAULT ((1)),
  [rowguid] [uniqueidentifier] ROWGUIDCOL  NOT NULL CONSTRAINT [DF_USERS_rowguid]  DEFAULT (newid()) ,
  [ModifiedDate] [datetime] NOT NULL CONSTRAINT [DF_USERS_ModifiedDate]  DEFAULT (getdate()) CONSTRAINT [CK_USERS_ModifiedDate] CHECK  ([ModifiedDate] > GETDATE()-1),
 CONSTRAINT [PK_USERS_USERID] PRIMARY KEY CLUSTERED
(
  [UserID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[USERS] ADD CONSTRAINT [UX_USERS_OwnerId] UNIQUE ([OwnerId])
GO
DROP TABLE IF EXISTS  [dbo].[Books]
CREATE TABLE [dbo].[Books](
  [BookNo] [BIGINT] NOT NULL,
  [Name] [nvarchar](50) NOT NULL,
  [Owner] [bigint] NOT NULL CONSTRAINT [FK_Books_Users_UserId]   FOREIGN KEY([Owner]) REFERENCES [dbo].[USERS] ([OwnerId]),
  [FolderFlag] [bit] NOT NULL CONSTRAINT [DF_Books_FolderFlag]  DEFAULT ((1)),
  [rowguid] [uniqueidentifier] ROWGUIDCOL  NOT NULL CONSTRAINT [DF_Books_rowguid]  DEFAULT (newid()) ,
  [ModifiedDate] [datetime] NOT NULL CONSTRAINT [DF_BOOKS_ModifiedDate]  DEFAULT (getdate()) CONSTRAINT [CK_BOOKS_ModifiedDate] CHECK  ([ModifiedDate] > GETDATE()-1),
 CONSTRAINT [PK_Books_BookNo_Owner] PRIMARY KEY CLUSTERED
(
  [BookNo] ASC,[Owner] DESC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
 CONSTRAINT [UK_Books_rowguid] UNIQUE NONCLUSTERED
(
  [rowguid] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
--LETS ADD FUNCTION TO ADD ONE UNIQUE INDEX, THIS IS JUST TO USE AS A DEFAULT CONSTRAINT ON [NationalNo] IN [dbo].[USERS] TABLE
DROP FUNCTION IF EXISTS [dbo].[ufnGetNationalOrBookNo]
GO
CREATE FUNCTION  [dbo].[ufnGetNationalOrBookNo](@ID INT)
RETURNS BIGINT
AS
BEGIN
DECLARE @NationalNo    BIGINT,@BookNo BIGINT,@ReturnNo BIGINT,@OwnerNo BIGINT;
SELECT @NationalNo = MIN([NationalNo])-1 FROM  [dbo].[USERS]
SELECT @BookNo = MIN([BookNo])-1 FROM  [dbo].[BOOKS]
SELECT @OwnerNo = MIN([OwnerId])-1 FROM  [dbo].[USERS]
IF (@ID =1 ) SELECT @ReturnNo = ISNULL(@NationalNo,1111111111111111111)
IF (@ID =2 ) SELECT @ReturnNo = ISNULL(@BookNo,1111111111111111111)
IF (@ID =3 ) SELECT @ReturnNo = ISNULL(@OwnerNo,1111111111111111111)
RETURN @ReturnNo;
END;
GO
ALTER TABLE [dbo].[Books] CHECK CONSTRAINT [FK_Books_Users_UserId]
GO
ALTER TABLE [dbo].[USERS]  ADD  CONSTRAINT [DF_Users_NationalNo]  DEFAULT (([dbo].[ufnGetNationalOrBookNo](1))) FOR [NationalNo]
GO
ALTER TABLE [dbo].[USERS]  ADD  CONSTRAINT [DF_Users_OwnerId]  DEFAULT (([dbo].[ufnGetNationalOrBookNo](3))) FOR [OwnerId]
GO
ALTER TABLE [dbo].[Books]  ADD  CONSTRAINT [DF_Books_BookNo]  DEFAULT (([dbo].[ufnGetNationalOrBookNo](2))) FOR [BookNo]
GO
CREATE UNIQUE NONCLUSTERED INDEX [AK_Users_NationalNo_UserID] ON [dbo].[USERS] ( [NationalNo] ASC,[UserID] DESC)
GO
CREATE UNIQUE NONCLUSTERED INDEX [UX_Users_NationalNo] ON [dbo].[USERS] ( [NationalNo] ASC,[UserID] DESC) INCLUDE ([NAME],[ModifiedDate]) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_USERS_NAME_OrganizationNode] ON [dbo].[USERS] ([NAME] DESC,[ActiveFlag] ASC ) INCLUDE ([ModifiedDate],[NationalNo]) ON [PRIMARY]
GO


































Load the sample data into the sample tables.

USE Game_001
GO
INSERT [dbo].[USERS] ([NAME])
SELECT 'NARA GAME_001 USER RECORD'
GO 300
GO
INSERT [dbo].[BOOKS]  ([Name],[Owner]) 
SELECT 'NARA GAME_001 BOOK RECORD',[OwnerId] FROM [dbo].[USERS]
GO


Clone one more game database with the same schema, RESEED the identity and load the data.
USE MASTER 
GO 
IF EXISTS (SELECT * FROM SYS.sysdatabases WHERE name = 'GAME_100') 
ALTER DATABASE GAME_100 SET  SINGLE_USER WITH ROLLBACK IMMEDIATE 
GO 
DROP DATABASE IF EXISTS GAME_100 
GO 
DBCC CLONEDATABASE(GAME_001,GAME_100) 
GO 
ALTER DATABASE [GAME_100] SET  READ_WRITE WITH NO_WAIT 
GO 
USE GAME_100 
GO 
--RESEED IDENTITY COLUMNS AFTER CLONING THE DATABASE 
IF(OBJECT_ID('tempdb..#ReseedIdentity') IS NOT NULL) DROP TABLE #ReseedIdentity 
SELECT DISTINCT IDENT_SEED(QUOTENAME(T.TABLE_SCHEMA)+'.'+QUOTENAME(T.TABLE_NAME)) AS Seed,T.TABLE_SCHEMA,
IDENT_INCR(QUOTENAME(T.TABLE_SCHEMA)+'.'+QUOTENAME(T.TABLE_NAME)) AS Increment,T.TABLE_NAME, 
COLUMNPROPERTY(OBJECT_ID(QUOTENAME(T.TABLE_SCHEMA)+'.'+QUOTENAME(T.TABLE_NAME)), C.COLUMN_NAME,'ISIDENTITY') AS Ident
INTO #ReseedIdentity 
FROM INFORMATION_SCHEMA.TABLES T 
JOIN INFORMATION_SCHEMA.COLUMNS C ON T.TABLE_NAME = C.TABLE_NAME AND T.TABLE_SCHEMA = C.TABLE_SCHEMA
WHERE COLUMNPROPERTY(OBJECT_ID(QUOTENAME(T.TABLE_SCHEMA)+'.'+QUOTENAME(T.TABLE_NAME)),C.COLUMN_NAME,'ISIDENTITY') = 1 AND
T.TABLE_TYPE = 'BASE TABLE' 
WHILE EXISTS (SELECT * FROM #ReseedIdentity) 
BEGIN 
  DECLARE @SQLCMD NVARCHAR(MAX),@TABLE_NAME SYSNAME,@TABLE_SCHEMA SYSNAME,@SEED INT 
  SELECT TOP 1 @TABLE_SCHEMA = TABLE_SCHEMA,@TABLE_NAME =TABLE_NAME,@SEED= SEED FROM #ReseedIdentity
  SELECT @SQLCMD =' DBCC CHECKIDENT (''['+@TABLE_SCHEMA+'].['+@TABLE_NAME+']'', RESEED, '+CAST(@SEED-1 AS varchar)+')' 
  --PRINT @SQLCMD 
  EXEC(@SQLCMD) 
  DELETE #ReseedIdentity WHERE TABLE_SCHEMA = @TABLE_SCHEMA AND TABLE_NAME = @TABLE_NAME 
END 
GO 
INSERT [dbo].[USERS] ([NAME]) 
SELECT 'NARA GAME_100 USER RECORD' 
GO 500 
GO 
INSERT [dbo].[BOOKS]  ([Name],[Owner]) 
SELECT 'NARA GAME_100 BOOK RECORD',[OwnerId] FROM [dbo].[USERS] 
GO























Let's check the number of records in GAME_100 records
2. Clone COMMON_GAME database from one of the sample game database.
USE MASTER 
GO 
IF EXISTS (SELECT * FROM SYS.sysdatabases WHERE name = 'COMMON_GAME') 
ALTER DATABASE COMMON_GAME SET  SINGLE_USER WITH ROLLBACK IMMEDIATE 
GO 
DROP DATABASE IF EXISTS COMMON_GAME 
GO 
DBCC CLONEDATABASE(GAME_001,COMMON_GAME) 
GO 
ALTER DATABASE [COMMON_GAME] SET  READ_WRITE WITH NO_WAIT 
GO 
USE COMMON_GAME 
GO 
--RESEED IDENTITY COLUMNS AFTER CLONING THE DATABASE 
IF(OBJECT_ID('tempdb..#ReseedIdentity') IS NOT NULL) DROP TABLE #ReseedIdentity 
SELECT DISTINCT IDENT_SEED(QUOTENAME(T.TABLE_SCHEMA)+'.'+QUOTENAME(T.TABLE_NAME)) AS Seed,T.TABLE_SCHEMA,
IDENT_INCR(QUOTENAME(T.TABLE_SCHEMA)+'.'+QUOTENAME(T.TABLE_NAME)) AS Increment,T.TABLE_NAME, 
COLUMNPROPERTY(OBJECT_ID(QUOTENAME(T.TABLE_SCHEMA)+'.'+QUOTENAME(T.TABLE_NAME)), C.COLUMN_NAME,'ISIDENTITY') AS Ident
INTO #ReseedIdentity 
FROM INFORMATION_SCHEMA.TABLES T 
JOIN INFORMATION_SCHEMA.COLUMNS C ON T.TABLE_NAME = C.TABLE_NAME AND T.TABLE_SCHEMA = C.TABLE_SCHEMA
WHERE COLUMNPROPERTY(OBJECT_ID(QUOTENAME(T.TABLE_SCHEMA)+'.'+QUOTENAME(T.TABLE_NAME)),C.COLUMN_NAME,'ISIDENTITY') = 1 AND
T.TABLE_TYPE = 'BASE TABLE' 
WHILE EXISTS (SELECT * FROM #ReseedIdentity) 
BEGIN 
  DECLARE @SQLCMD NVARCHAR(MAX),@TABLE_NAME SYSNAME,@TABLE_SCHEMA SYSNAME,@SEED INT 
  SELECT TOP 1 @TABLE_SCHEMA = TABLE_SCHEMA,@TABLE_NAME =TABLE_NAME,@SEED= SEED FROM #ReseedIdentity
  SELECT @SQLCMD =' DBCC CHECKIDENT (''['+@TABLE_SCHEMA+'].['+@TABLE_NAME+']'', RESEED, '+CAST(@SEED-1 AS varchar)+')' 
  --PRINT @SQLCMD 
  EXEC(@SQLCMD) 
  DELETE #ReseedIdentity WHERE TABLE_SCHEMA = @TABLE_SCHEMA AND TABLE_NAME = @TABLE_NAME 
END 
GO

































3. ADD GAME_NO column (to distinguish each database records) in all tables of COMMON_GAME database.

Please make sure to NOT to add GAME_NO column in all domain/master/lookup tables.
USE COMMON_GAME
GO
--ADD NEW COLUMNS IN ALL TABLES IN COMMON DATAABSE
IF (OBJECT_ID('tempdb..#alltables') IS NOT NULL) DROP TABLE #alltables
SELECT TABLE_SCHEMA,TABLE_NAME INTO #alltables FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'
WHILE EXISTS (SELECT * FROM #alltables)
BEGIN
DECLARE @TABLE_SCHEMA SYSNAME,@TABLE_NAME SYSNAME,@SQLCMD NVARCHAR(MAX)
SELECT TOP 1 @TABLE_SCHEMA= TABLE_SCHEMA, @TABLE_NAME = TABLE_NAME FROM #alltables
SELECT @SQLCMD = 'IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = ''GAME_NO'' AND TABLE_NAME = '''+@TABLE_NAME+''' AND TABLE_SCHEMA = '''+@TABLE_SCHEMA+''')  ALTER TABLE ['+@TABLE_SCHEMA+'].['+@TABLE_NAME+'] ADD GAME_NO SMALLINT NOT NULL'
--PRINT @SQLCMD
EXEC SP_EXECUTESQL @SQLCMD
DELETE #alltables WHERE TABLE_NAME = @TABLE_NAME AND TABLE_SCHEMA = @TABLE_SCHEMA
END
GO




















4. Update the Primary key constraints in COMMON_GAME database except for Identity Keys.
I have made an assumption here that No Identity key is part of the foreign key.

USE COMMON_GAME
GO
IF(OBJECT_ID('tempdb..#PrimayKeyONIdentity') IS NOT NULL) DROP TABLE #PrimayKeyONIdentity
SELECT DISTINCT T.TABLE_CATALOG,T.TABLE_SCHEMA,T.TABLE_NAME,CTU.CONSTRAINT_NAME
INTO #PrimayKeyONIdentity
FROM COMMON_GAME.INFORMATION_SCHEMA.TABLES T
JOIN COMMON_GAME.INFORMATION_SCHEMA.COLUMNS C ON C.TABLE_CATALOG = T.TABLE_CATALOG AND T.TABLE_NAME = C.TABLE_NAME AND T.TABLE_SCHEMA = C.TABLE_SCHEMA
JOIN COMMON_GAME.INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE CTU ON CTU.TABLE_CATALOG = T.TABLE_CATALOG AND CTU.TABLE_SCHEMA = T.TABLE_SCHEMA
AND CTU.TABLE_NAME = T.TABLE_NAME
WHERE COLUMNPROPERTY(OBJECT_ID(QUOTENAME(T.TABLE_SCHEMA)+'.'+QUOTENAME(T.TABLE_NAME)),C.COLUMN_NAME,'ISIDENTITY') = 1 AND
T.TABLE_TYPE = 'BASE TABLE'IF(OBJECT_ID('tempdb..#PRIMARYKEY_CONSTRAINTS') IS NOT NULL) DROP TABLE #PRIMARYKEY_CONSTRAINTS
SELECT INDEX_NAME CONSTRAINT_NAME,
'IF EXISTS (SELECT * FROM COMMON_GAME.INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE WHERE CONSTRAINT_NAME = '''+(INDEX_NAME)+''' AND TABLE_SCHEMA = '''+(TABLE_SCHEMA)+''' AND TABLE_NAME = '''+(TABLE_NAME)+''' AND TABLE_CATALOG =''COMMON_GAME'') ALTER TABLE '+QUOTENAME(TABLE_SCHEMA)+'.'+QUOTENAME(TABLE_NAME)+' DROP CONSTRAINT'+ QUOTENAME(INDEX_NAME) + CHAR(13)+
'ALTER TABLE '+  QUOTENAME(TABLE_SCHEMA) +'.'+ QUOTENAME(TABLE_NAME)+ ' ADD CONSTRAINT ' +  QUOTENAME(INDEX_NAME) + IS_UNIQUE_CONSTRAINT + IS_PRIMARY_KEY + INDEX_TYPE_DESC +  '('+[INDEX_COLUMNS]+' ,[GAME_NO] DESC ) '
-- +case when len([INCLUDED_COLUMNS])>0 then CHAR(13) +'INCLUDE (' + [INCLUDED_COLUMNS]+ ')' else '' end + CHAR(13)+'WITH (' + INDEXOPTIONS+ ') ON ' + QUOTENAME(FILEGROUPNAME) + ';'  
 AS SQLCMD INTO #PRIMARYKEY_CONSTRAINTS
 FROM (
SELECT DISTINCT SCHEMA_NAME(ST.SCHEMA_ID) TABLE_SCHEMA, ST.NAME TABLE_NAME, SIX.NAME INDEX_NAME,
CASE WHEN SIX.IS_UNIQUE = 1 THEN ' UNIQUE ' ELSE '' END AS IS_UNIQUE,
CASE WHEN SIX.IS_UNIQUE_CONSTRAINT = 1 THEN ' UNIQUE ' ELSE '' END AS IS_UNIQUE_CONSTRAINT
,CASE WHEN SIX.IS_PRIMARY_KEY = 1 THEN ' PRIMARY KEY ' ELSE '' END AS IS_PRIMARY_KEY
, SIX.TYPE_DESC COLLATE DATABASE_DEFAULT  INDEX_TYPE_DESC,
  CASE  WHEN SIX.IS_PADDED=1 THEN 'PAD_INDEX = ON, ' ELSE 'PAD_INDEX = OFF, ' END
 + CASE WHEN SIX.ALLOW_PAGE_LOCKS=1 THEN 'ALLOW_PAGE_LOCKS = ON, ' ELSE 'ALLOW_PAGE_LOCKS = OFF, ' END
 + CASE WHEN SIX.ALLOW_ROW_LOCKS=1 THEN  'ALLOW_ROW_LOCKS = ON, ' ELSE 'ALLOW_ROW_LOCKS = OFF, ' END
 + CASE WHEN INDEXPROPERTY(ST.OBJECT_ID, SIX.NAME, 'ISSTATISTICS') = 1 THEN 'STATISTICS_NORECOMPUTE = ON, ' ELSE 'STATISTICS_NORECOMPUTE = OFF, ' END
 + CASE WHEN SIX.IGNORE_DUP_KEY=1 THEN 'IGNORE_DUP_KEY = ON, ' ELSE 'IGNORE_DUP_KEY = OFF ' END
 --+ ', SORT_IN_TEMPDB = OFF '+ CASE WHEN IX.FILL_FACTOR > 0 THEN ',FILLFACTOR =' + CAST(IX.FILL_FACTOR AS VARCHAR(3)) ELSE ' ' END 
 AS INDEXOPTIONS,FILEGROUP_NAME(SIX.DATA_SPACE_ID) FILEGROUPNAME
 ,STUFF(REPLACE((SELECT '~~' + QUOTENAME(COL.NAME)+ ' '+ CASE WHEN IXC.IS_DESCENDING_KEY =1 THEN 'DESC' ELSE 'ASC' END  AS 'data()'
 FROM SYS.TABLES T
JOIN SYS.INDEXES IX ON T.OBJECT_ID=IX.OBJECT_ID
JOIN SYS.INDEX_COLUMNS IXC ON IX.OBJECT_ID=IXC.OBJECT_ID AND IX.INDEX_ID= IXC.INDEX_ID
JOIN SYS.COLUMNS COL ON IXC.OBJECT_ID =COL.OBJECT_ID  AND IXC.COLUMN_ID=COL.COLUMN_ID
  WHERE IX.TYPE>0 AND (SIX.IS_PRIMARY_KEY=1  OR SIX.IS_UNIQUE_CONSTRAINT=1) AND IXC.IS_INCLUDED_COLUMN <> 1 AND  COL.NAME<> 'GAME_NO'
AND SCHEMA_NAME(T.SCHEMA_ID) = SCHEMA_NAME(ST.SCHEMA_ID) AND T.NAME = ST.NAME AND IX.NAME = SIX.NAME
FOR XML PATH('')),'~~',', '), 1, 2, '') as [INDEX_COLUMNS]
--CASE WHEN LEN(INCLUDED_COLUMN) >1 THEN 
--STUFF(REPLACE((SELECT '~~' + LTRIM(RTRIM(INCLUDED_COLUMN)) AS 'data()' FROM #INDEXCOLUMNS IC WHERE IC.INDEXNAME = I.INDEXNAME
--FOR XML PATH('')),'~~',', '), 1, 2, '') ELSE '' END as [INCLUDED_COLUMNS]
,ISNULL(STUFF(REPLACE((SELECT '~~' + QUOTENAME(COL.NAME) AS 'data()' FROM SYS.TABLES T
JOIN SYS.INDEXES IX ON T.OBJECT_ID=IX.OBJECT_ID
JOIN SYS.INDEX_COLUMNS IXC ON IX.OBJECT_ID=IXC.OBJECT_ID AND IX.INDEX_ID= IXC.INDEX_ID
JOIN SYS.COLUMNS COL ON IXC.OBJECT_ID =COL.OBJECT_ID  AND IXC.COLUMN_ID=COL.COLUMN_ID
  WHERE IX.TYPE>0 AND (SIX.IS_PRIMARY_KEY=1  OR SIX.IS_UNIQUE_CONSTRAINT=1) AND IXC.IS_INCLUDED_COLUMN = 1 AND  COL.NAME<> 'GAME_NO'
AND SCHEMA_NAME(T.SCHEMA_ID) = SCHEMA_NAME(ST.SCHEMA_ID) AND T.NAME = ST.NAME AND IX.NAME = SIX.NAME
FOR XML PATH('')),'~~',', '), 1, 2, ''),'') as [INCLUDED_COLUMNS]
 FROM SYS.TABLES ST INNER JOIN SYS.INDEXES SIX ON ST.OBJECT_ID=SIX.OBJECT_ID
 WHERE SIX.TYPE>0 AND (  SIX.IS_PRIMARY_KEY=1  OR SIX.IS_UNIQUE_CONSTRAINT=1)
 AND ST.IS_MS_SHIPPED=0 AND ST.NAME<>'SYSDIAGRAMS'
 ) A WHERE  INDEX_NAME NOT IN (SELECT CONSTRAINT_NAME FROM #PrimayKeyONIdentity)
WHILE EXISTS (SELECT * FROM #PRIMARYKEY_CONSTRAINTS)
BEGIN
  DECLARE @SQLCMD NVARCHAR(MAX),@CONSTRAINT_NAME VARCHAR(500)
  SELECT TOP 1 @CONSTRAINT_NAME = CONSTRAINT_NAME ,@SQLCMD = SQLCMD FROM #PRIMARYKEY_CONSTRAINTS
  PRINT @SQLCMD
  EXEC(@SQLCMD)
  DELETE #PRIMARYKEY_CONSTRAINTS WHERE CONSTRAINT_NAME = @CONSTRAINT_NAME
END
GO

















5. Update the Foreign key constraints in COMMON_GAME database.

USE COMMON_GAME
GO
IF(OBJECT_ID('tempdb..#ForeignKeys') IS NOT NULL) DROP TABLE #ForeignKeys
SELECT CONSTRAINT_NAME,--UC_CONSTRAINT_NAME,UC_TABLE_SCHEMA,UC_TABLE_NAME,
'IF NOT EXISTS (SELECT  * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME = '''+'UX_'+REFERENCED_TABLE_NAME+'_'+REPLACE(REPLACE(REPLACE([REFERENCED_COLUMNS],',','_'),'[',''),']','')+'_GAME_NO'''+') ALTER TABLE '+QUOTENAME([REFERENCED_TABLE_SCHEMA])+'.'+QUOTENAME([REFERENCED_TABLE_NAME])+' ADD CONSTRAINT [UX_'+REFERENCED_TABLE_NAME+'_'+REPLACE(REPLACE(REPLACE([REFERENCED_COLUMNS],',','_'),'[',''),']','')+'_GAME_NO'+'] UNIQUE (' +[REFERENCED_COLUMNS]+',[GAME_NO] )'+
'IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME = ''' +CONSTRAINT_NAME +''')   ALTER TABLE '+QUOTENAME(TABLE_SCHEMA)+'.'+QUOTENAME(TABLE_NAME) + ' DROP CONSTRAINT ' +QUOTENAME(CONSTRAINT_NAME)+'  ALTER TABLE '+QUOTENAME(TABLE_SCHEMA)+'.'+QUOTENAME(TABLE_NAME)+' WITH CHECK ADD CONSTRAINT '+QUOTENAME(CONSTRAINT_NAME)
+' FOREIGN KEY('+[COLUMNS]+',[GAME_NO] ) REFERENCES '
+ QUOTENAME([REFERENCED_TABLE_SCHEMA])+'.'+QUOTENAME([REFERENCED_TABLE_NAME]) + '  ( '+[REFERENCED_COLUMNS] + ',[GAME_NO]  ) '+
CASE WHEN UC_CONSTRAINT_NAME IS NOT NULL AND UC_CONSTRAINT_NAME NOT LIKE '%_GAME_NO' THEN 'IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME = ''' +UC_CONSTRAINT_NAME +''')   ALTER TABLE '+QUOTENAME(UC_TABLE_SCHEMA)+'.'+QUOTENAME(UC_TABLE_NAME) + ' DROP CONSTRAINT ' +QUOTENAME(UC_CONSTRAINT_NAME) ELSE '' END AS SQLCMD
INTO #ForeignKeys FROM (
SELECT DISTINCT TC.CONSTRAINT_NAME,TC.TABLE_SCHEMA,TC.TABLE_NAME [TABLE_NAME],TC2.TABLE_SCHEMA AS [REFERENCED_TABLE_SCHEMA],TC2.TABLE_NAME [REFERENCED_TABLE_NAME]
   ,STUFF(REPLACE((SELECT '~~' + QUOTENAME(COLUMN_NAME) AS 'data()' FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE IC
WHERE IC.CONSTRAINT_NAME = KCU.CONSTRAINT_NAME AND COLUMN_NAME<> 'GAME_NO' ORDER BY ORDINAL_POSITION
FOR XML PATH('')),'~~',', '), 1, 2, '') as [COLUMNS]
,STUFF(REPLACE((SELECT '~~' + QUOTENAME(COLUMN_NAME) AS 'data()' FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE IC
WHERE IC.CONSTRAINT_NAME = KCU2.CONSTRAINT_NAME AND COLUMN_NAME<> 'GAME_NO'  ORDER BY ORDINAL_POSITION
FOR XML PATH('')),'~~',', '), 1, 2, '') as [REFERENCED_COLUMNS],
UC.CONSTRAINT_NAME AS UC_CONSTRAINT_NAME,UC.TABLE_SCHEMA UC_TABLE_SCHEMA,UC.TABLE_NAME UC_TABLE_NAME
FROM   INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU  ON TC.CONSTRAINT_SCHEMA = KCU.CONSTRAINT_SCHEMA AND TC.CONSTRAINT_NAME = KCU.CONSTRAINT_NAME
JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC ON TC.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA AND TC.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC2 ON RC.UNIQUE_CONSTRAINT_SCHEMA = TC2.CONSTRAINT_SCHEMA AND RC.UNIQUE_CONSTRAINT_NAME = TC2.CONSTRAINT_NAME
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU2 ON TC2.CONSTRAINT_SCHEMA = KCU2.CONSTRAINT_SCHEMA AND TC2.CONSTRAINT_NAME = KCU2.CONSTRAINT_NAME
AND KCU.ORDINAL_POSITION = KCU2.ORDINAL_POSITION
LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS UC ON UC.TABLE_SCHEMA = TC2.TABLE_SCHEMA AND UC.TABLE_NAME =TC2.TABLE_NAME
WHERE  TC.CONSTRAINT_TYPE ='FOREIGN KEY' AND UC.CONSTRAINT_TYPE ='UNIQUE'
) A
WHILE EXISTS (SELECT * FROM #ForeignKeys)
BEGIN
DECLARE @CONSTRAINT_NAME VARCHAR(500),@SQLCMD NVARCHAR(MAX)
SELECT TOP 1 @CONSTRAINT_NAME = CONSTRAINT_NAME,@SQLCMD = SQLCMD FROM #ForeignKeys
PRINT @SQLCMD
EXEC (@SQLCMD)
DELETE #ForeignKeys WHERE CONSTRAINT_NAME = @CONSTRAINT_NAME
END
GO


















6. Update the Indexes in COMMON_GAME database.

USE COMMON_GAME
GO
IF(OBJECT_ID('tempdb..#INDEX_SCRIPT') IS NOT NULL) DROP TABLE #INDEX_SCRIPT
SELECT INDEX_NAME,'IF EXISTS (SELECT * FROM SYS.INDEXES WHERE NAME = '''+INDEX_NAME+''') DROP INDEX '+QUOTENAME(INDEX_NAME)+' ON ' + QUOTENAME(TABLE_SCHEMA) +'.'+ QUOTENAME(TABLE_NAME)+
' CREATE '+ IS_UNIQUE  +INDEX_TYPE_DESC + ' INDEX ' +QUOTENAME(INDEX_NAME)+' ON ' + QUOTENAME(TABLE_SCHEMA) +'.'+ QUOTENAME(TABLE_NAME)+ '('+[INDEX_COLUMNS]+' , [GAME_NO] DESC ) '+
  case when [INCLUDED_COLUMNS]<>'' then CHAR(13) +'INCLUDE (' + [INCLUDED_COLUMNS]+ ')' else '' end + CHAR(13)+'WITH (' + INDEXOPTIONS+ ') ON ' + QUOTENAME(FILEGROUPNAME) + ';' SQLCMD
INTO #INDEX_SCRIPT FROM (
SELECT DISTINCT SCHEMA_NAME(ST.SCHEMA_ID) TABLE_SCHEMA, ST.NAME TABLE_NAME, SIX.NAME INDEX_NAME,
CASE WHEN SIX.IS_UNIQUE = 1 THEN ' UNIQUE ' ELSE '' END AS IS_UNIQUE
, SIX.TYPE_DESC COLLATE DATABASE_DEFAULT  INDEX_TYPE_DESC,
  CASE  WHEN SIX.IS_PADDED=1 THEN 'PAD_INDEX = ON, ' ELSE 'PAD_INDEX = OFF, ' END
 + CASE WHEN SIX.ALLOW_PAGE_LOCKS=1 THEN 'ALLOW_PAGE_LOCKS = ON, ' ELSE 'ALLOW_PAGE_LOCKS = OFF, ' END
 + CASE WHEN SIX.ALLOW_ROW_LOCKS=1 THEN  'ALLOW_ROW_LOCKS = ON, ' ELSE 'ALLOW_ROW_LOCKS = OFF, ' END
 + CASE WHEN INDEXPROPERTY(ST.OBJECT_ID, SIX.NAME, 'ISSTATISTICS') = 1 THEN 'STATISTICS_NORECOMPUTE = ON, ' ELSE 'STATISTICS_NORECOMPUTE = OFF, ' END
 + CASE WHEN SIX.IGNORE_DUP_KEY=1 THEN 'IGNORE_DUP_KEY = ON, ' ELSE 'IGNORE_DUP_KEY = OFF ' END
 --+ ', SORT_IN_TEMPDB = OFF '+ CASE WHEN IX.FILL_FACTOR > 0 THEN ',FILLFACTOR =' + CAST(IX.FILL_FACTOR AS VARCHAR(3)) ELSE ' ' END 
 AS INDEXOPTIONS,FILEGROUP_NAME(SIX.DATA_SPACE_ID) FILEGROUPNAME
 ,STUFF(REPLACE((SELECT '~~' + QUOTENAME(COL.NAME)+ ' '+ CASE WHEN IXC.IS_DESCENDING_KEY =1 THEN 'DESC' ELSE 'ASC' END  AS 'data()'
 FROM SYS.TABLES T
JOIN SYS.INDEXES IX ON T.OBJECT_ID=IX.OBJECT_ID
JOIN SYS.INDEX_COLUMNS IXC ON IX.OBJECT_ID=IXC.OBJECT_ID AND IX.INDEX_ID= IXC.INDEX_ID
JOIN SYS.COLUMNS COL ON IXC.OBJECT_ID =COL.OBJECT_ID  AND IXC.COLUMN_ID=COL.COLUMN_ID
  WHERE IX.TYPE>0 AND (IX.IS_PRIMARY_KEY=0 AND IX.IS_UNIQUE_CONSTRAINT=0) AND IXC.IS_INCLUDED_COLUMN <> 1 AND  COL.NAME<> 'GAME_NO'
AND SCHEMA_NAME(T.SCHEMA_ID) = SCHEMA_NAME(ST.SCHEMA_ID) AND T.NAME = ST.NAME AND IX.NAME = SIX.NAME
FOR XML PATH('')),'~~',', '), 1, 2, '') as [INDEX_COLUMNS]
,ISNULL(STUFF(REPLACE((SELECT '~~' + QUOTENAME(COL.NAME) AS 'data()' FROM SYS.TABLES T
JOIN SYS.INDEXES IX ON T.OBJECT_ID=IX.OBJECT_ID
JOIN SYS.INDEX_COLUMNS IXC ON IX.OBJECT_ID=IXC.OBJECT_ID AND IX.INDEX_ID= IXC.INDEX_ID
JOIN SYS.COLUMNS COL ON IXC.OBJECT_ID =COL.OBJECT_ID  AND IXC.COLUMN_ID=COL.COLUMN_ID
  WHERE IX.TYPE>0 AND (IX.IS_PRIMARY_KEY=0 AND IX.IS_UNIQUE_CONSTRAINT=0) AND IXC.IS_INCLUDED_COLUMN = 1 AND  COL.NAME<> 'GAME_NO'
AND SCHEMA_NAME(T.SCHEMA_ID) = SCHEMA_NAME(ST.SCHEMA_ID) AND T.NAME = ST.NAME AND IX.NAME = SIX.NAME
FOR XML PATH('')),'~~',', '), 1, 2, ''),'') as [INCLUDED_COLUMNS]
 FROM SYS.TABLES ST INNER JOIN SYS.INDEXES SIX ON ST.OBJECT_ID=SIX.OBJECT_ID
 WHERE SIX.TYPE>0 AND ( SIX.IS_PRIMARY_KEY=0  AND SIX.IS_UNIQUE_CONSTRAINT=0)
 AND ST.IS_MS_SHIPPED=0 AND ST.NAME<>'SYSDIAGRAMS'  ) A
WHILE EXISTS (SELECT * FROM #INDEX_SCRIPT)
BEGIN
  DECLARE @SQLCMD NVARCHAR(MAX),@INDEX_NAME VARCHAR(500)
  SELECT TOP 1 @INDEX_NAME = INDEX_NAME ,@SQLCMD = SQLCMD FROM #INDEX_SCRIPT
  PRINT @SQLCMD
  EXEC(@SQLCMD)
  DELETE #INDEX_SCRIPT WHERE INDEX_NAME = @INDEX_NAME
END
GO































7. [Optional Step] Create Partition Schema and Partition Function on GAME_NO

Since I have created GAME_100 that means there are 100 databases are becoming cold and will have to move the data to COMMON_GAME database. Here, I am creating 100 partition functions and you can also attach 100 file groups while creating a Partition Scheme. 

USE [COMMON_GAME]
GO
IF NOT EXISTS (SELECT * FROM SYS.PARTITION_FUNCTIONS WHERE NAME = 'PF_GAME_NO')
CREATE PARTITION FUNCTION [PF_GAME_NO](SMALLINT) AS RANGE LEFT FOR VALUES
( N'1',  N'2',  N'3',  N'4' ,N'5' ,N'6',N'7',N'8',N'9',N'10' ,
  N'11', N'12', N'13', N'14',N'15',N'16',N'17',N'18',N'19',N'20' ,
  N'21', N'22', N'23', N'24',N'25',N'26',N'27',N'28',N'29',N'30' ,
  N'31', N'32', N'33', N'34',N'35',N'36',N'37',N'38',N'39',N'40' ,
  N'41', N'42', N'43', N'44',N'45',N'46',N'47',N'48',N'49',N'50' ,
  N'51', N'52', N'53', N'54',N'55',N'56',N'57',N'58',N'59',N'60' ,
  N'61', N'62', N'63', N'64',N'65',N'66',N'67',N'68',N'69',N'70' ,
  N'71', N'72', N'73', N'74',N'75',N'76',N'77',N'78',N'79',N'80' ,
  N'81', N'82', N'83', N'84',N'85',N'86',N'87',N'88',N'89',N'90' ,
  N'91', N'92', N'93', N'94',N'95',N'96',N'97',N'98',N'99',N'100' )
GO
IF NOT EXISTS (SELECT * FROM SYS.PARTITION_SCHEMES WHERE NAME = 'PS_GAME_NO')
CREATE PARTITION SCHEME [PS_GAME_NO] AS PARTITION [PF_GAME_NO] ALL TO ([PRIMARY])
GO
IF (OBJECT_ID('tempdb..#alltables') IS NOT NULL) DROP TABLE #alltables
SELECT TABLE_SCHEMA,TABLE_NAME INTO #alltables FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'
WHILE EXISTS (SELECT * FROM #alltables)
BEGIN
DECLARE @TABLE_SCHEMA SYSNAME,@TABLE_NAME SYSNAME,@SQLCMD NVARCHAR(MAX)
SELECT TOP 1 @TABLE_SCHEMA= TABLE_SCHEMA, @TABLE_NAME = TABLE_NAME FROM #alltables
SELECT @SQLCMD = 'IF NOT EXISTS (SELECT * FROM SYS.INDEXES WHERE NAME = ''IX_'+@TABLE_NAME+'_GAME_NO'')  CREATE NONCLUSTERED INDEX [IX_'+@TABLE_NAME+'_GAME_NO] ON '+QUOTENAME(@TABLE_SCHEMA)+'.'+QUOTENAME(@TABLE_NAME)+' (GAME_NO) ON PS_GAME_NO(GAME_NO)'
PRINT @SQLCMD
EXEC SP_EXECUTESQL @SQLCMD
DELETE #alltables WHERE TABLE_NAME = @TABLE_NAME AND TABLE_SCHEMA = @TABLE_SCHEMA
END
GO

























8. Load the data into COMMON_GAME database from all individual GAME_*** databases and rename the tables (*_Old) after loading the data.

If the table is domain/master/lookup table which has the same data in all databases. You can copy that table data manually. Add the following filter after highlighted green " AND TABLE_NAME=''<TABLE_NAME>'' ".
Please make sure to update/add/replace database name in the highlighted filter before executing the query.
--COPY DATA FROM ALL GAMES INTO COMMON DATABASE AND AND RENAME THE TABLE (AS A BACKUP) IN INDIVIDUAL GAME DATABASES 
USE COMMON_GAME
GO
IF (OBJECT_ID('tempdb..#allgames') IS NOT NULL) DROP TABLE #allgames
SELECT name into #allgames FROM SYS.sysdatabases WHERE name IN ('GAME_001','GAME_100')
WHILE EXISTS (SELECT * FROM #allgames)
BEGIN
  DECLARE @DatabaseName SYSNAME,@TABLE_CATALOG SYSNAME,@TABLE_SCHEMA SYSNAME,@TABLE_NAME SYSNAME,@COLUMNS_LIST NVARCHAR(MAX)
  SELECT top 1 @DatabaseName = name FROM  #allgames
  DECLARE @SQLTableCommnd NVARCHAR(MAX)
  IF (OBJECT_ID('tempdb..##tableInfo') IS NOT NULL) DROP TABLE ##tableInfo
SET @SQLTableCommnd = 'SELECT DISTINCT T.TABLE_CATALOG,T.TABLE_SCHEMA,T.TABLE_NAME, STUFF(REPLACE((SELECT ''~~'' + QUOTENAME(SC.COLUMN_NAME) AS ''data()''   FROM  ['+@DatabaseName+']. INFORMATION_SCHEMA.COLUMNS SC   WHERE SC.TABLE_SCHEMA =C.TABLE_SCHEMA AND SC.TABLE_NAME=C.TABLE_NAME AND    COLUMNPROPERTY(OBJECT_ID(QUOTENAME(SC.TABLE_SCHEMA)+''.''+QUOTENAME(SC.TABLE_NAME)),SC.COLUMN_NAME,''ISIDENTITY'') <> 1 AND   COLUMNPROPERTY(OBJECT_ID(QUOTENAME(SC.TABLE_SCHEMA)+''.''+QUOTENAME(SC.TABLE_NAME)),SC.COLUMN_NAME,''IsComputed'') <> 1 AND   SC.COLUMN_NAME<> ''GAME_NO''  FOR XML PATH('''')),''~~'','', ''), 1, 2, '''') as [COLUMNS_LIST], ISNULL(DEPENDENCY_LEVEL,0) AS DEPENDENCY_LEVEL INTO ##tableInfo FROM  ['+@DatabaseName+']. INFORMATION_SCHEMA.TABLES T  JOIN   ['+@DatabaseName+']. INFORMATION_SCHEMA.COLUMNS C ON C.TABLE_SCHEMA = T.TABLE_SCHEMA AND C.TABLE_NAME = T.TABLE_NAME LEFT JOIN (SELECT TC.TABLE_SCHEMA,TC.TABLE_NAME [TABLE_NAME],999 DEPENDENCY_LEVEL FROM  ['+@DatabaseName+']. INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC  JOIN  ['+@DatabaseName+']. INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU  ON TC.CONSTRAINT_SCHEMA = KCU.CONSTRAINT_SCHEMA AND TC.CONSTRAINT_NAME = KCU.CONSTRAINT_NAME  JOIN  ['+@DatabaseName+']. INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC ON TC.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA AND TC.CONSTRAINT_NAME = RC.CONSTRAINT_NAME  WHERE  TC.CONSTRAINT_TYPE = ''FOREIGN KEY'') FK ON FK.TABLE_SCHEMA = T.TABLE_SCHEMA AND FK.TABLE_NAME = T.TABLE_NAME WHERE TABLE_TYPE=''BASE TABLE'' ORDER BY ISNULL(DEPENDENCY_LEVEL,0)'
   --PRINT @SQLTableCommnd
  EXEC SP_EXECUTESQL @SQLTableCommnd
  WHILE EXISTS (SELECT * FROM ##tableInfo )
  BEGIN
  SELECT TOP 1 @TABLE_CATALOG =TABLE_CATALOG ,@TABLE_SCHEMA=TABLE_SCHEMA,@TABLE_NAME=TABLE_NAME,@COLUMNS_LIST = COLUMNS_LIST FROM ##tableInfo ORDER BY DEPENDENCY_LEVEL
  SET @SQLTableCommnd = 'INSERT [COMMON_GAME].['+@TABLE_SCHEMA+'].['+@TABLE_NAME+'] ('+@COLUMNS_LIST+',[GAME_NO])  SELECT '+@COLUMNS_LIST+','
  +CONVERT(VARCHAR,CAST(SUBSTRING(@TABLE_CATALOG,6,LEN(@TABLE_CATALOG)) AS INT))+'  FROM ['+@TABLE_CATALOG+'].['+@TABLE_SCHEMA+'].['+@TABLE_NAME+']  (NOLOCK)'
   PRINT @SQLTableCommnd
  EXEC SP_EXECUTESQL @SQLTableCommnd
  SET @SQLTableCommnd = @TABLE_CATALOG+'.'+@TABLE_SCHEMA+'.'+'SP_RENAME '''+@TABLE_NAME+''', '''+@TABLE_NAME+'_old'''
  PRINT @SQLTableCommnd
  EXEC (@SQLTableCommnd)
  DELETE ##tableInfo WHERE TABLE_CATALOG= @TABLE_CATALOG AND TABLE_SCHEMA= @TABLE_SCHEMA AND TABLE_NAME = @TABLE_NAME
  END
  DELETE #allgames WHERE name=@DatabaseName
END
GO
























9. Verify the data in COMMON_GAME database and drop the *_Old tables from individual game databases.
select count(*) from GAME_001.dbo.[USERS_Old]
select count(*) from GAME_001.dbo.[Books_Old]
select count(*) from GAME_100.dbo.[USERS_Old]
select count(*) from GAME_100.dbo.[Books_Old]
select count(*) from COMMON_GAME.dbo.[USERS]
select count(*) from COMMON_GAME.dbo.[Books]





































Drop the "*_old" tables from individual game databases. try to drop the tables based on dependency order or try executing multiple times to drop dependent tables after getting the error.


USE master
GO
IF (OBJECT_ID('tempdb..#allgames') IS NOT NULL) DROP TABLE #allgames
SELECT name into #allgames FROM SYS.sysdatabases WHERE name IN ('GAME_001','GAME_100')
WHILE EXISTS (SELECT * FROM #allgames)
BEGIN
  DECLARE @DatabaseName SYSNAME,@TABLE_CATALOG SYSNAME,@TABLE_SCHEMA SYSNAME,@TABLE_NAME SYSNAME
  SELECT top 1 @DatabaseName = name FROM  #allgames
  DECLARE @SQLTableCommnd NVARCHAR(MAX)
  IF (OBJECT_ID('tempdb..##tableInfo') IS NOT NULL) DROP TABLE ##tableInfo
  SET @SQLTableCommnd = 'SELECT * INTO ##tableInfo FROM ['+@DatabaseName+']. INFORMATION_SCHEMA.TABLES WHERE  TABLE_TYPE=''BASE TABLE'''
  EXEC SP_EXECUTESQL @SQLTableCommnd
  WHILE EXISTS (SELECT * FROM ##tableInfo)
  BEGIN
  SELECT TOP 1 @TABLE_CATALOG =TABLE_CATALOG ,@TABLE_SCHEMA=TABLE_SCHEMA,@TABLE_NAME=TABLE_NAME FROM ##tableInfo
  SET @SQLTableCommnd = 'DROP TABLE '+QUOTENAME(@TABLE_CATALOG)+'.'+QUOTENAME(@TABLE_SCHEMA)+'.'+QUOTENAME(@TABLE_NAME)
   PRINT @SQLTableCommnd
  EXEC SP_EXECUTESQL @SQLTableCommnd
  DELETE ##tableInfo WHERE TABLE_CATALOG= @TABLE_CATALOG AND TABLE_SCHEMA= @TABLE_SCHEMA AND TABLE_NAME = @TABLE_NAME
  END
  DELETE #allgames WHERE name=@DatabaseName
END
GO
10.Create views and triggers in all the individual game databases.
Below script would create views (NOT included identity keys in columns) and INSTEAD OF INSERT trigger. Please make sure NOT to add GAME_NO column for all domain/master/lookup view (role-playing dimensions) or try creating the domain/master/lookup views manually.

--CREATE VIEWS IN INDVIDUAL GAME DATABASES
USE COMMON_GAME
GO
IF (OBJECT_ID('tempdb..#VIEWINFO') IS NOT NULL) DROP TABLE #VIEWINFO
SELECT DISTINCT T.TABLE_CATALOG,T.TABLE_SCHEMA,T.TABLE_NAME,
STUFF(REPLACE((SELECT '~~' + QUOTENAME(SC.COLUMN_NAME) AS 'data()'
 FROM  INFORMATION_SCHEMA.COLUMNS SC
  WHERE SC.TABLE_SCHEMA =C.TABLE_SCHEMA AND SC.TABLE_NAME=C.TABLE_NAME AND SC.COLUMN_NAME<> 'GAME_NO'  AND
  COLUMNPROPERTY(OBJECT_ID(QUOTENAME(SC.TABLE_SCHEMA)+'.'+QUOTENAME(SC.TABLE_NAME)),SC.COLUMN_NAME,'ISIDENTITY') <> 1
    ORDER BY SC.ORDINAL_POSITION
FOR XML PATH('')),'~~',', '), 1, 2, '') as [COLUMNS_LIST] INTO #VIEWINFO
FROM  INFORMATION_SCHEMA.TABLES T  JOIN
INFORMATION_SCHEMA.COLUMNS C ON C.TABLE_SCHEMA = T.TABLE_SCHEMA AND C.TABLE_NAME = T.TABLE_NAME
WHERE TABLE_TYPE='BASE TABLE'
IF (OBJECT_ID('tempdb..#allgamedbs') IS NOT NULL) DROP TABLE #allgamedbs
SELECT name AS DBNAME, VF.*  INTO #allgamedbs FROM SYS.sysdatabases CROSS APPLY  #VIEWINFO VF WHERE name IN ('GAME_001','GAME_100')
WHILE EXISTS (SELECT * FROM #allgamedbs)
BEGIN
  DECLARE @DatabaseName SYSNAME,@TABLE_CATALOG SYSNAME,@TABLE_SCHEMA SYSNAME,@TABLE_NAME SYSNAME,@COLUMNS_LIST NVARCHAR(MAX),@SQLCMD NVARCHAR(MAX),@SQLVIEW NVARCHAR(MAX)
  SELECT top 1 @DatabaseName = DBNAME,@TABLE_CATALOG =TABLE_CATALOG,@TABLE_SCHEMA=TABLE_SCHEMA,
  @TABLE_NAME=TABLE_NAME,@COLUMNS_LIST = COLUMNS_LIST FROM  #allgamedbs
  --DROP VIEW IF EXITS 
  SET  @SQLCMD = 'IF EXISTS (SELECT * FROM '+QUOTENAME(@DatabaseName)+'.INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME ='''''+@TABLE_NAME+''''' AND TABLE_SCHEMA = '''''+@TABLE_SCHEMA+''''')   DROP VIEW '+QUOTENAME(@TABLE_SCHEMA)+'.'+QUOTENAME(@TABLE_NAME)
  SET @SQLVIEW =' EXEC ' +@DatabaseName+'.'+'SYS.'+'SP_EXECUTESQL  @STMT= N''' + @SQLCMD +''''
  --PRINT @SQLVIEW
  EXEC (@SQLVIEW)
  --CREATE VIEW
  SET  @SQLCMD ='CREATE VIEW  '+QUOTENAME(@TABLE_SCHEMA)+'.'+QUOTENAME(@TABLE_NAME) +' AS SELECT '+@COLUMNS_LIST +' FROM ' +QUOTENAME(@TABLE_CATALOG)+'.'+QUOTENAME(@TABLE_SCHEMA)+'.'+QUOTENAME(@TABLE_NAME) + ' (NOLOCK) WHERE GAME_NO= '+ CONVERT(VARCHAR,CAST(SUBSTRING(@DatabaseName,6,LEN(@DatabaseName)) AS INT)) + ''
  SET @SQLVIEW =' EXEC ' +@DatabaseName+'.'+'SYS.'+'SP_EXECUTESQL  @STMT= N''' + @SQLCMD +''''
  --PRINT @SQLVIEW
  EXEC (@SQLVIEW)
  --DROP TRIGGER IF EXISTS
  SET  @SQLCMD = 'IF EXISTS (SELECT * FROM '+QUOTENAME(@DatabaseName)+'.SYS.TRIGGERS  WHERE NAME ='''''+'TRG_'+@TABLE_NAME+''''' )   DROP TRIGGER '+QUOTENAME(@TABLE_SCHEMA)+'.[TRG_'+(@TABLE_NAME)+']'
  SET @SQLVIEW =' EXEC ' +@DatabaseName+'.'+'SYS.'+'SP_EXECUTESQL  @STMT= N''' + @SQLCMD +''''
  --PRINT @SQLVIEW
  EXEC (@SQLVIEW)
  --CREATE TRIGGER
  SET  @SQLCMD ='CREATE TRIGGER  '+QUOTENAME(@TABLE_SCHEMA)+'.[TRG_'+(@TABLE_NAME) +'] ON '+ QUOTENAME(@DatabaseName)+'.'+QUOTENAME(@TABLE_SCHEMA)+'.'+QUOTENAME(@TABLE_NAME)+'   INSTEAD OF INSERT AS BEGIN INSERT INTO '+QUOTENAME(@TABLE_CATALOG)+'.'+QUOTENAME(@TABLE_SCHEMA)+'.'+QUOTENAME(@TABLE_NAME) +'   ( '+@COLUMNS_LIST +',[GAME_NO]) SELECT '+@COLUMNS_LIST +',CAST(SUBSTRING(DB_NAME(),6,LEN(DB_NAME()))  AS SMALLINT) FROM INSERTED END'
  SET @SQLVIEW =' EXEC ' +@DatabaseName+'.'+'SYS.'+'SP_EXECUTESQL  @STMT= N''' + @SQLCMD +''''
  --PRINT @SQLVIEW
  EXEC (@SQLVIEW)

  DELETE #allgamedbs WHERE DBNAME =@DatabaseName AND TABLE_SCHEMA =@TABLE_SCHEMA AND TABLE_NAME=@TABLE_NAME
END
GO


























 11. Validate the INSERT and UPDATE statements.
Insert Validation:
SELECT COUNT(*) ROW_CNT_BEFORE FROM COMMON_GAME.DBO.[USERS] WHERE GAME_NO = 1
USE [Game_001]
GO
SELECT COUNT(*) ROW_CNT_BEFORE_INSERT FROM [dbo].[USERS]
GO
INSERT [dbo].[USERS] ([NationalNo],[OwnerId],[NAME],[ActiveFlag],[rowguid],[ModifiedDate])
SELECT '1111111111111110811','1111111111111110811', 'NARA GAME_001 USER RECORD INSERTING FROM VIEW',1, NEWID(),GETDATE()
GO
SELECT COUNT(*) ROW_CNT_AFTER_INSERT FROM [dbo].[USERS]
GO
SELECT COUNT(*) ROW_CNT_AFTER FROM COMMON_GAME.DBO.[USERS] WHERE GAME_NO = 1

























Try Insert record in Books Table
SELECT COUNT(*) ROW_CNT_BEFORE FROM COMMON_GAME.DBO.[Books] WHERE GAME_NO = 1
USE [Game_001]
GO
INSERT [dbo].[Books] ([BookNo],[Name],[Owner],[FolderFlag],[rowguid],[ModifiedDate])
SELECT '1111111111111111111','NARA GAME_100 USER RECORD INSERTING FROM VIEW','
1111111111111110811',1,NEWID(),GETDATE()
GO
SELECT COUNT(*) ROW_CNT_AFTER_INSERT FROM [dbo].[Books]
GO
SELECT COUNT(*) ROW_CNT_AFTER FROM COMMON_GAME.DBO.[Books] WHERE GAME_NO = 1




















Insert records in GAME_100 database

SELECT COUNT(*) ROW_CNT_BEFORE FROM COMMON_GAME.DBO.[USERS] WHERE GAME_NO = 1
USE [Game_100]
GO
SELECT COUNT(*) ROW_CNT_BEFORE_INSERT FROM [dbo].[USERS]
GO
INSERT [dbo].[USERS] ([NationalNo],[OwnerId],[NAME],[ActiveFlag],[rowguid],[ModifiedDate])
SELECT '1111111111111110611','1111111111111110611', 'NARA GAME_100 USER RECORD INSERTING FROM VIEW',1, NEWID(),GETDATE()
GO
SELECT COUNT(*) ROW_CNT_AFTER_INSERT FROM [dbo].[USERS]
GO
SELECT COUNT(*) ROW_CNT_AFTER FROM COMMON_GAME.DBO.[USERS] WHERE GAME_NO = 1

SELECT COUNT(*) ROW_CNT_BEFORE FROM COMMON_GAME.DBO.[USERS] WHERE GAME_NO = 100
USE [Game_100]
GO
SELECT COUNT(*) ROW_CNT_BEFORE_INSERT FROM [dbo].[USERS]
GO
INSERT [dbo].[USERS] ([NationalNo],[OwnerId],[NAME],[ActiveFlag],[rowguid],[ModifiedDate])
SELECT '1111111111111110611','1111111111111110611', 'NARA GAME_100 USER RECORD INSERTING FROM VIEW',1, NEWID(),GETDATE()
GO
SELECT COUNT(*) ROW_CNT_AFTER_INSERT FROM [dbo].[USERS]
GO
SELECT COUNT(*) ROW_CNT_AFTER FROM COMMON_GAME.DBO.[USERS] WHERE GAME_NO = 100
GO
SELECT COUNT(*) ROW_CNT_BEFORE FROM COMMON_GAME.DBO.[Books] WHERE GAME_NO = 100
USE [Game_100]
GO
INSERT [dbo].[Books] ([BookNo],[Name],[Owner],[FolderFlag],[rowguid],[ModifiedDate])
SELECT '1111111111111111111','NARA GAME_100 USER RECORD INSERTING FROM VIEW','1111111111111110611',1,NEWID(),GETDATE()
GO
SELECT COUNT(*) ROW_CNT_AFTER_INSERT FROM [dbo].[Books]
GO
SELECT COUNT(*) ROW_CNT_AFTER FROM COMMON_GAME.DBO.[Books] WHERE GAME_NO = 100












































Update Validation:
USE GAME_100
GO
UPDATE GAME_100.DBO.Books  SET [Name] = 'UPDATING GAME_100 VALUE TO NARA'
SELECT @@ROWCOUNT
GO
SELECT COUNT(*) GAME_1_ROWS   FROM  COMMON_GAME.DBO.Books WHERE [GAME_NO] = '100' AND [Name] = 'UPDATING GAME_100 VALUE TO NARA'
SELECT COUNT(*) AS TOTAL_ROWS FROM  COMMON_GAME.DBO.Books
GO






















Achieved?. Let me know if you think otherwise
12.  Maintenance GOING FORWARD when the game database becomes COLD and ready to move to COMMON_GAME database.
Let's say that GAME_101 database becomes COLD and ready to move to COMMON_GAME database. Please follow the below steps in order to make GAME_101 cold.

[Optional Step] Create Additional partition.
USE COMMON_GAME
GO
ALTER PARTITION SCHEME [PS_GAME_NO]
 NEXT USED [PRIMARY]
ALTER PARTITION FUNCTION [PF_GAME_NO]() SPLIT RANGE(N'101')


Follow the below steps in order as explained above by replacing the "WHERE name IN ('GAME_001','GAME_100')to "WHERE name IN ('GAME_101')"

8. Load the data into COMMON_GAME database from all individual GAME_*** databases and rename the tables (*_Old) after loading the data.
9. Verify the data in COMMON_GAME database and drop the *_Old tables from individual game databases.
10. Create views and triggers in all the individual game databases.

Achieved?. Let me know if you think otherwise

Please feel free to use any of the above scripts in case if suits for your scenarios. Let me know if you find anything wrong in the script/post. Mistakes can happen 😊 .

CONCLUSION:

By following this approach, you would get below benefits
  1. Store the domain/master/lookup tables data in a single place, which can be used by all COLD databases (Role Playing Dimensions).
  2. Can automate moving the databases to COLD based on certain conditions( maybe after 1 year or 2 years) by using the same scripts in a Job.
  3. Users, Reports or Applications would not be having any impact as they access AS-IS to the enterprise server.
  4. Can keep all COLD databases in a separate SQL INSTANCE and update the views to point to other SQL INSTANCE by creating a linked server.
Thanks