How to move tables from one sql server database to another? - sql

We have a database that has grown to about 50GB and we want to pull out a certain set of tables (about 20 of them) from within that database and move them into a new database. All of this would be on the same SQL Server. The tables that we want to pull out are about 12GB of space (6GB data, 6GB indexes).
How can we move the tables from one database to the second but make sure the tables that are created in the new database are an exact copy of the originals (indexes, keys, etc.)? Ideally I want a copy/paste from within SQL Server Management Studio but I know this does not exist, so what are my options?

To do this really easily with SQL Server 2008 Management Studio:
1.) Right click on the database (not the table) and select Tasks -> Generate Scripts
2.) Click Next on the first page
3.) If you want to copy the whole database, just click next. If you want to copy specific tables, click on "Select Specific Database Objects", select the tables you want, and then click next.
4.) Select "Save to Clipboard" or "Save to File". IMPORTANT: Click the Advanced button next to "Save to File", find "Types of data to script", and change "Schema only" to "Schema and data" (if you want to create the table) or "Data only" (if you're copying data to an existing table). This is also where you'd set other options such as exactly what keys to copy, etc.
5.) Click through the rest and you're done!

If you're moving the tables to a whole new database just because of growth, you might be better off considering using filegroups in your existing database instead. There will be a lot fewer headaches going forward than trying to deal with two separate databases.
EDIT
As I mentioned in my comments below, if you truly need a new database, depending on the total number of tables involved, it might be easier to restore a backup of the database under the new name and drop the tables you don't want.

I did also find this potential solution using SQL Server Management Studio. You can generate the scripts for the specific tables to move and then export the data using the Generate Scripts Wizard and Import/Export Wizard in SQL Server Management Studio. Then on the new database you would run the scripts to create all of the objects and then import the data. We are probably going to go with the backup/restore method as described in #Joe Stefanelli's answer but I did find this method and wanted to post it for others to see.
To generate the sql script for the objects:
SQL Server Management Studio > Databases > Database1 > Tasks > Generate Scripts...
The SQL Server Scripts Wizard will start and you can choose the objects and settings to export into scripts
By default the scripting of Indexes and Triggers are not included so make sure to trun these on (and any others that you are interested in).
To export the data from the tables:
SQL Server Management Studio > Databases > Database1 > Tasks > Export Data...
Choose the source and destination databases
Select the tables to export
Make sure to check the Identity Insert checkbox for each table so that new identities are not created.
Then create the new database, run the scripts to create all of the objects, and then import the data.

If you like/have SSIS you can explore using the Copy SQL Objects Task component to do this.

Try DBSourceTools.
http://dbsourcetools.codeplex.com.
This toolset uses SMO to script tables and data to disk, and also allows you to select which tables / views / Stored procedures to include.
When using a "deployment target", it will also automatically handle dependencies.
I have used it repeatedly for exactly this type of problem, and it's extremely simple and fast.

SELECT *
INTO new_table_name [IN new database]
FROM old_tablename

A lazy, efficient way to do this in T-SQL:
In my case, some of the tables are large, so scripting out the data is impractical.
Also, we needed to migrate just a fraction of an otherwise very large database, so I didn't want to do backup / restore.
So I went with INSERT INTO / SELECT FROM and used information_schema etc to generate the code.
Step 1: create your tables on new DB
For every table you want to migrate to new database, create that table on new database.
Either script out the tables, or use SQL Compare, dynamic sql from information_schema -- many ways to do it. dallin's answer shows one way using SSMS (but be sure to select schema only).
Step 2: create UDF on target DB to produce column list
This is just a helper function used in generation of code.
USE [staging_edw]
GO
CREATE FUNCTION dbo.udf_get_column_list
(
#table_name varchar(8000)
)
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE #var VARCHAR(8000)
SELECT
#var = COALESCE(#var + ',', '', '') + c.COLUMN_NAME
FROM INFORMATION_SCHEMA.columns c
WHERE c.TABLE_SCHEMA + '.' + c.TABLE_NAME = #table_name
AND c.COLUMN_NAME NOT LIKE '%hash%'
RETURN #var
END
Step 3: create log table
The generated code will log progress into this table so you can monitor. But you have to create this log table first.
USE staging_edw
GO
IF OBJECT_ID('dbo.tmp_sedw_migration_log') IS NULL
CREATE TABLE dbo.tmp_sedw_migration_log
(
step_number INT IDENTITY,
step VARCHAR(100),
start_time DATETIME
)
Step 4: generate migration script
Here you generate the T-SQL that will migrate the data for you. It just generates INSERT INTO / SELECT FROM statements for every table, and logs its progress along the way.
This script does not actually modify anything. It just outputs some code, which you can inspect before executing.
USE staging_edw
GO
-- newline characters for formatting of generated code
DECLARE #n VARCHAR(100) = CHAR(13)+CHAR(10)
DECLARE #t VARCHAR(100) = CHAR(9)
DECLARE #2n VARCHAR(100) = #n + #n
DECLARE #2nt VARCHAR(100) = #n + #n + #t
DECLARE #nt VARCHAR(100) = #n + #t
DECLARE #n2t VARCHAR(100) = #n + #t + #t
DECLARE #2n2t VARCHAR(100) = #n + #n + #t + #t
DECLARE #3n VARCHAR(100) = #n + #n + #n
-- identify tables with identity columns
IF OBJECT_ID('tempdb..#identities') IS NOT NULL
DROP TABLE #identities;
SELECT
table_schema = s.name,
table_name = o.name
INTO #identities
FROM sys.objects o
JOIN sys.columns c on o.object_id = c.object_id
JOIN sys.schemas s ON s.schema_id = o.schema_id
WHERE 1=1
AND c.is_identity = 1
-- generate the code
SELECT
#3n + '-- ' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME,
#n + 'BEGIN TRY',
#2nt + IIF(i.table_schema IS NOT NULL, 'SET IDENTITY_INSERT staging_edw.' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME + ' ON ', ''),
#2nt + 'TRUNCATE TABLE staging_edw.' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME,
#2nt + 'INSERT INTO staging_edw.' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME + ' WITH (TABLOCKX) ( ' + f.f + ' ) ',
#2nt + 'SELECT ' + f.f + + #nt + 'FROM staging.' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME,
#2nt + IIF(i.table_schema IS NOT NULL, 'SET IDENTITY_INSERT staging_edw.' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME + ' OFF ', ''),
#2nt + 'INSERT INTO dbo.tmp_sedw_migration_log ( step, start_time ) VALUES ( ''' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME + ' inserted successfully'', GETDATE() );' ,
#2n + 'END TRY',
#2n + 'BEGIN CATCH',
#2nt + 'INSERT INTO dbo.tmp_sedw_migration_log ( step, start_time ) VALUES ( ''' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME + ' FAILED'', GETDATE() );' ,
#2n + 'END CATCH'
FROM INFORMATION_SCHEMA.tables t
OUTER APPLY (SELECT f = staging_edw.dbo.udf_get_column_list(t.TABLE_SCHEMA + '.' + t.TABLE_NAME)) f
LEFT JOIN #identities i ON i.table_name = t.TABLE_NAME
AND i.table_schema = t.TABLE_SCHEMA
WHERE t.TABLE_TYPE = 'base table'
Step 5: run the code
Now you just copy the output from step 4, paste into new query window, and run.
Notes
In step 1, I exclude hash columns from the column list (in the UDF) because those are computed columns in my situation

Related

How to create an alias of database in SQL Server

We have a very old software has been created around 10 years ago and we don't have source code.
The software uses two databases, DB01 and DB02 on the same SQL Server 2012 instance.
There is SQL statements such as db01..table1 join db02..table2, but the main issue is our processes don't allow us use db02 as a name of database.
The question is: how we can create an alias of for database?
I was trying to use CREATE SYNONYM
CREATE SYNONYM [db02] FOR [db02_new_name];
but it doesn't work for database names.
Please suggest how it can be solved without patching a binary files to correct SQL statements.
Create a database with the name you want to impersonate. Re-jigg the DDL code generator to create a view for every table in the database that has the tables I need to access via the hardcoded name. Basically, each view will have a statement that looks like this..
CREATE VIEW schemaname.tablename as SELECT * FROM targetdbname.schemaname.tablename
Example:
The target database name that is hardcoded is called ProdDBV1 and the Source DB you have is named ProductDatabaseDatabaseV1, schema is dbo and table name is customer
Create the database called ProdDBV1 using SSMS or script.
CREATE VIEW dbo.customer as SELECT * FROM ProductDatabaseDatabaseV1.dbo.customer
If you can enumerate each table in your "source" database and then create the DDL as above. If you want I can update this posting with a code example. (using the sp_msforeachtable procedure if possible)
I had a similar issue.
Solved with this workaround, using synonyms.
Short version: You flood your database with a synonym of every object you'll ever need to reference. Later you re-create every synonym with the other database name.
Here's a stored proc to do it. Simply add it to your database and call it with the target database. It will create synonyms for all tables in the target database, and create the schemas if they don't exist. I've left a commented out section in case someone knows of a way to get the create schemas working without a cursor.
CREATE PROCEDURE CreateSynonymsForTargetDatabase (
#databaseName sysname
)
AS BEGIN
DECLARE #TSQL nvarchar(max) = N''
DECLARE #rn char(2),
#SchemaName sysname;
SET #rn = char(13) + char(10)
CREATE TABLE #DBSynonym(
[Schema] sysname NOT NULL,
[Table] sysname NOT NULL
)
SET #TSQL = N'
INSERT INTO #DBSynonym ([Schema], [Table])
SELECT Schemas.name, Tables.name
FROM [' + #databaseName + '].sys.tables
INNER JOIN [' + #databaseName + '].sys.schemas on tables.schema_id = schemas.schema_id
'
EXEC (#TSQL)
SET #TSQL = N''
DECLARE MissingSchemasCursor CURSOR
READ_ONLY
FOR
SELECT newSchemas.[Schema]
FROM #DBSynonym newSchemas
LEFT JOIN sys.schemas on newSchemas.[Schema] = schemas.name
WHERE schemas.schema_id is null
GROUP BY newSchemas.[Schema]
OPEN MissingSchemasCursor
FETCH NEXT FROM MissingSchemasCursor INTO #SchemaName
WHILE (##fetch_status <> -1)
BEGIN
IF (##fetch_status <> -2)
BEGIN
SET #TSQL = N'CREATE SCHEMA ' + QUOTENAME(#SchemaName) + N';'
EXEC sp_executesql #TSQL
END
FETCH NEXT FROM MissingSchemasCursor INTO #SchemaName
END
CLOSE MissingSchemasCursor
DEALLOCATE MissingSchemasCursor
/*
SELECT #TSQL = #TSQL +
N'
GO
CREATE SCHEMA ' + QUOTENAME([Schema]) + N';'
FROM #DBSynonym newSchemas
LEFT JOIN sys.schemas on newSchemas.[Schema] = schemas.name
WHERE schemas.schema_id is null
GROUP BY newSchemas.[Schema]
PRINT 'CREATE SCHEMAS : ' + ISNULL(#TSQL,'')
EXEC sp_executesql #TSQL
*/
SET #TSQL = N''
SELECT #TSQL = #TSQL +
N'
CREATE SYNONYM ' + QUOTENAME([Schema]) + N'.' + QUOTENAME([Table]) + N'
FOR ' + QUOTENAME(#databaseName) + N'.' + QUOTENAME([Schema]) + N'.' + QUOTENAME([Table]) + N';'
FROM #DBSynonym
EXEC sp_executesql #TSQL
SET #TSQL = N''
END
GO
Use it as follows :
EXEC CreateSynonymsForTargetDatabase 'targetDbName'
The question is: how we can create an alias of for database?
I know this is an old post but...
This is why I only use the 2 part naming convention for SQL objects. It allows me to have 2 part synonyms that point to differently named databases depending on what environment I'm in. There are some places where it doesn't work so well but, for the most part, those places are very rare.
As for software that you don't have the source code of and if that software uses the 3 part naming convention, you're probably just out of luck unless you know what the 3 part naming convention is for each object and create a 3 part synonym for each object.
I found Charles' answer (and the linked workaround in the comment by maxcastaneda) very useful. I followed this approach and it works for me. I have streamlined it a bit and created the following query that brings up all required synonyms to create.
As a prerequisite for this snippet both the original DB and the synonym/alias db have to be on the same server otherwise in case you use linked server or so you have to modify it a bit.
It should be fairly easy to put this into a small sp to update the synonyms automatically.
USE <SYNONYMDB>
SELECT
'[' + TABLE_NAME + ']',
'[' + TABLE_SCHEMA + '].[' + TABLE_NAME + ']',
'IF EXISTS (SELECT * FROM sys.synonyms WHERE name = ''' + TABLE_NAME + ''') DROP SYNONYM ['+ TABLE_NAME + ']; CREATE SYNONYM [' + TABLE_NAME + '] FOR <ORIGINALDB>.' + TABLE_SCHEMA + '.[' + TABLE_NAME + ']' AS SynonymUpdateScript FROM <ORIGINALDB>.INFORMATION_SCHEMA.TABLES
Don't forget to enter you Db names at the <...> spots.
Just copy the content of the SynonymUpdateScript Column and execute it in the synonym DB - or create a stored procedure for this task.
Be aware there is an issue if you have views in place that refer to tables or other db objects without the 2 part naming convention. Those synonyms won't work. You should fix this in the original objects / views.
Go to the Database you wish to create Alias,
Create an Alias Folders table with the preferred design,
Go to unique IDs's table and check the last code sequence for the table created.
For example, if the last code is 10, then update it to 11.
Open Cabinets table and go right at the bottom and create the name of the Alias cabinet you want.
You can create an alias from 'SQL Server Configuration Manager' under Configuartion Tool in SQL Server Folder.
Detailed source : http://www.mssqltips.com/sqlservertip/1620/how-to-setup-and-use-a-sql-server-alias/
http://technet.microsoft.com/en-us/library/ms190445.aspx

SQL Server Generate Scripts

I need to find a way to generate insert select scripts for a set of tables. The Generate Scripts Task in SSMS 2008 seems to generate insert values statements. I could just generate them using some of the system views but would prefer to functionality for this already in SSMS
Thanks
What do you want to do? Generate script for Insert or Select? Right click on the table choose 'Script table as' and choose what you want to do
In Object Explorer, pick your database, use Tasks > Generate Scripts.. and then click on the Advanced Options button:
In the dialog that comes up, you can pick what to script - schema only, data only or schema and data:
You could use this script:
--assuming only the db instance differs
declare #otherDB varchar(100) = 'instanceB'
declare #thisDB varchar(100) = db_name()
select
'INSERT INTO ' + #otherDB + '.' + s.name + '.' + t.name +
' SELECT * FROM ' + #thisDB + '.' + s.name + '.' + t.name
from sys.tables t
inner join sys.schemas s on s.schema_id = t.schema_id
where t.is_ms_shipped = 0

Sql Server change fill factor value for all indexes by tsql

I have to expoet my DB into a bacpac file to import it into Azure.
When I try to export I get an error because any indexes have a fillFactor value.
I've found how to set a fillFactor value for all indexes but I can't specify 0, the value have to be between 1 an 100. If I change the value in the management studio I can set it to 0.
The problem is that I have got lots of indexes to change and I would like to change the fillFactor value to all of them trough tsql.
Any ideas?.
Thanks.
something simpler for all tables in a single database:
select 'ALTER INDEX ALL ON '
+ quotename(s.name) + '.' + quotename(o.name) + ' REBUILD WITH (FILLFACTOR = 99)'
from sys.objects o
inner join sys.schemas s on o.schema_id = s.schema_id
where type='u' and is_ms_shipped=0
generates statements you can then copy & execute.
This isn't a straight T-SQL way of doing it. Though it does generate a pure T-SQL solution that you can apply to your DB.
Your results may vary depending on your DB... For example poor referential integrity might make this a bit trickier..
Also this comes with a DO AT YOUR OWN RISK disclaimer :-)
Get the DB you want to migrate into an SSDT project
http://msdn.microsoft.com/en-us/library/azure/jj156163.aspx
http://blogs.msdn.com/b/ssdt/archive/2012/04/19/migrating-a-database-to-sql-azure-using-ssdt.aspx
This is a nice way to migrate any schema to Azure regardless... It's way better then just creating a bacpac file.. fixing... exporting...fixing.. etc... So I would recommend doing this anytime you want to migrate a DB to Azure
For the FILLFACTOR fixes I just used a find and replace to remove all the FILLFACTORS from the generated schema files... Luckily the DB I was using had them all set to 90 so it was fairly easy to do a solution wide find and replace (CTRL-SHIFT-F)... If yours vary then you can probably use the RegEx find features of Visual Studio to find all the fillfactors and just remove them from the indexes.
I'm not that great at RegEx but I think this works
WITH \((.)*FILLFACTOR(.)*\)
At this point you'll have to fix any additional exceptions around Azure compliance.. The links provided describe how to go about doing this
Now that you're at the point where you have an SSDT project that's AZURE SQL compliant.
Here comes the DO AT YOUR OWN RISK PART
I used these scripts to remove all FK, PK, and Unique Constraints from the DB.
while(exists(select 1 from INFORMATION_SCHEMA.TABLE_CONSTRAINTS where CONSTRAINT_TYPE IN ('FOREIGN KEY', 'PRIMARY KEY', 'UNIQUE')))
begin
declare #sql nvarchar(2000)
SELECT TOP 1 #sql=('ALTER TABLE ' + TABLE_SCHEMA + '.[' + TABLE_NAME
+ '] DROP CONSTRAINT [' + CONSTRAINT_NAME + ']')
FROM information_schema.table_constraints
WHERE CONSTRAINT_TYPE IN ('FOREIGN KEY', 'PRIMARY KEY', 'UNIQUE')
exec (#sql)
end
declare #qry nvarchar(max);
select #qry =
(SELECT 'DROP INDEX [' + ix.name + '] ON [' + OBJECT_NAME(ID) + ']; '
FROM sysindexes ix
WHERE ix.Name IS NOT null and ix.OrigFillFactor <> 0
for xml path(''));
exec sp_executesql #qry
I do this because AFAIK the only way to completely remove the fill factor option is to drop and re-create the index. This comes with a cascading set of issues :-/ PK's with fill factors need the FK's dropped etc.... There's probably a smarter way to do this so you don't remove ALL FK's and PK's and you look at the dependency trees...
Now go back to your Azure Compliant SSDT project and do a SCHEMA COMPARISON of that project against your DB... This will create a script that recreates all your FK's, PK's, and Unique Constraints (without the Fill Factor).... At this point you can just click "update" or you can click the button just to the right of update which will generate the script you can use... So now armed with
the script above to remove FKs, Pks, and Unique.
The script created by SSDT
Ample testing and review of said scripts to ensure nothing was missed
You should be able to update your current DB to an Azure compliant SCHEMA
Additional Thoughts:
In my case the fill factors on the Production DB weren't really doing anything useful. They were just created as a default thing to do. In your case the fill factors might be important so don't just remove them all on your non Azure Production box without knowing the consequences.
There's additional things to consider when doing this to a production system... For example this might cause some mirroring delays and it might cause your log files to grow in a way you aren't anticipating. Which both only really matter if you're applying directly to production...
It'd be nice if setting them all to FILL FACTOR 100 worked :-/
There's 3rd party tools out there (so I've heard) that you can use to migrate to Azure...
Another option is to use
https://sqlazuremw.codeplex.com/
Use that to create a SCHEMA that's Azure compliant and then it uses BCP to copy all the data.
BUT if you want to make your current SCHEMA Azure compliant so you can create a bacpac file to upload into Azure this worked for me the one time I've had to do it.
EDIT:
Azure V12 supports fill factors
SQL Azure apparently does not support FILLFACTOR:
"SQL Azure Database does not support specifying FILLFACTOR with the
CREATE INDEX statement. If we create indexes in a SQL Azure database,
we will find that the index fillfactor values are all 0."
You would have to remove all FILLFACTOR statements from the CREATE INDEX scripts. Likewise, SORT_IN_TEMPDB and DATA_COMPRESSION and several other options are also not supported.
A full list of supported keywords in SQL Azure can be found here.
Update: SQL Azure V12 (introduced in 2015) does support FILLFACTOR. See here.
I found a very useful script here that would do the job of assigning a new value to all indexes and rebuilding them. As long as you are not afraid if using dynamic T-SQL you might find it useful for your task and environment, just set the values appropriately.
(I didn't find the license information on the original page so I copy the script here)
DECLARE #Database VARCHAR(255)
DECLARE #Table VARCHAR(255)
DECLARE #cmd NVARCHAR(500)
DECLARE #fillfactor INT
SET #fillfactor = 90
DECLARE DatabaseCursor CURSOR FOR
SELECT name FROM master.dbo.sysdatabases
WHERE name NOT IN ('master','msdb','tempdb','model','distribution')
ORDER BY 1
OPEN DatabaseCursor
FETCH NEXT FROM DatabaseCursor INTO #Database
WHILE ##FETCH_STATUS = 0
BEGIN
SET #cmd = 'DECLARE TableCursor CURSOR FOR SELECT ''['' + table_catalog + ''].['' + table_schema + ''].['' +
table_name + '']'' as tableName FROM [' + #Database + '].INFORMATION_SCHEMA.TABLES
WHERE table_type = ''BASE TABLE'''
-- create table cursor
EXEC (#cmd)
OPEN TableCursor
FETCH NEXT FROM TableCursor INTO #Table
WHILE ##FETCH_STATUS = 0
BEGIN
IF (##MICROSOFTVERSION / POWER(2, 24) >= 9)
BEGIN
-- SQL 2005 or higher command
SET #cmd = 'ALTER INDEX ALL ON ' + #Table + ' REBUILD WITH (FILLFACTOR = ' + CONVERT(VARCHAR(3),#fillfactor) + ')'
EXEC (#cmd)
END
ELSE
BEGIN
-- SQL 2000 command
DBCC DBREINDEX(#Table,' ',#fillfactor)
END
FETCH NEXT FROM TableCursor INTO #Table
END
CLOSE TableCursor
DEALLOCATE TableCursor
FETCH NEXT FROM DatabaseCursor INTO #Database
END
CLOSE DatabaseCursor
DEALLOCATE DatabaseCursor
It seems you want to use the server default fill factor (0) which omits the FILLFACTOR statement from the creation scripts. There is no way to do this by just rebuilding the index, you must drop and re-create it (see here). There doesn't seem to be a clean way of doing this, though its kind of a moot point now.
ALTER INDEX yourindex ON table.column
REBUILD WITH (FILLFACTOR = 0);
does the job. 0 is equal to 100 (see http://msdn.microsoft.com/en-us/library/ms177459.aspx), meaning no gaps are left in the index.
you have to run this for every index. the rebuilding can take considerable time, though.

SQL Server 2008: create trigger across all tables in db

Using SQL Server 2008, I've created a database where every table has a datetime column called "CreatedDt". What I'd like to do is create a trigger for each table so that when a value is inserted, the CreatedDt column is populated with the current date and time.
If you'll pardon my pseudocode, what I'm after is the T-SQL equivalent of:
foreach (Table in MyDatabase)
{
create trigger CreatedDtTrigger
{
on insert createddt = datetime.now;
}
}
If anyone would care to help out, I'd greatly appreciate it. Thanks!
As #EricZ says, the best thing to do is bind a default for the column. Here's how you'd add it to every table using a cursor and dynamic SQL:
Sure, You can do it with a cursor:
declare #table sysname, #cmd nvarchar(max)
declare c cursor for
select name from sys.tables where is_ms_shipped = 0 order by name
open c; fetch next from c into #table
while ##fetch_status = 0
begin
set #cmd = 'ALTER TABLE ' + #table + ' ADD CONSTRAINT DF_' + #table + '_CreateDt DEFAULT GETDATE() FOR CreateDt'
exec sp_executesql #cmd
fetch next from c into #table
end
close c; deallocate c
No need to go for Cursors. Just copy the result of below Query and Execute.
select distinct 'ALTER TABLE '+ t.name +
' ADD CONSTRAINT DF_'+t.name+'_crdt DEFAULT getdate() FOR '+ c.name
from sys.tables t
inner join sys.columns c on t.object_id=c.object_id
where c.name like '%your column name%'
Here's another method:
DECLARE #SQL nvarchar(max);
SELECT #SQL = Coalesce(#SQL + '
', '')
+ 'ALTER TABLE ' + QuoteName(T.TABLE_SCHEMA) + '.' + QuoteName(T.TABLE_NAME)
+ ' ADD CONSTRAINT ' + QuoteName('DF_'
+ CASE WHEN T.TABLE_SCHEMA <> 'dbo' THEN T.Table_Schema + '_' ELSE '' END
+ C.COLUMN_NAME) + ' DEFAULT (GetDate()) FOR ' + QuoteName(C.COLUMN_NAME)
+ ';'
FROM
INFORMATION_SCHEMA.TABLES T
INNER JOIN INFORMATION_SCHEMA.COLUMNS C
ON T.TABLE_SCHEMA = C.TABLE_SCHEMA
AND T.TABLE_NAME = C.TABLE_NAME
WHERE
C.COLUMN_NAME = 'CreatedDt'
;
EXEC (#SQL);
This yields, and runs, a series of statements similar to the following:
ALTER TABLE [schema].[TableName] -- (line break added)
ADD CONSTRAINT [DF_schema_TableName] DEFAULT (GetDate()) FOR [ColumnName];
Some notes:
This uses the INFORMATION_SCHEMA views. It is best practice to use these where possible instead of the system tables because they are guaranteed to not change between versions of SQL Server (and moreover are supported on many DBMSes, so all things being equal it's best to use standards-compliant/portable code).
In a database with a case-sensitive default collation, one MUST use upper case for the INFORMATION_SCHEMA view names and column names.
When creating script it's important to pay attention to schema names and proper escaping (using QuoteName). Not doing so will break in someone's system some day.
I think it is best practice to put the DEFAULT expression inside parentheses. While no error is received without it in this case, with it, if the function GetDate() is parameterized and/or ever changed to a more complex expression, nothing will break.
If you decide that column defaults are not going to work for you, then the triggers you imagined are still possible. But it will take some serious work to manage whether the trigger already exists and alter or create it appropriately, JOIN to the inserted meta-table inside the trigger, and do it based on the full list of primary key columns for the table (if they exist, and if they don't, then you're out of luck). It is quite possible, but extremely difficult--you could end up with nested, nested, nested dynamic SQL. I have such automated object-creating script that contains 13 quote marks in a row...

I need to create a view that unions all tables based on their prefix (new tables added monthly)

The integration software that my client is using is pulling over ISAM files from a RMS system and creating lots of tables that all have identical schemas, but nonetheless the software they use doesn't support merging them together.
Here's some example table names:
SOME_TABLE_XYZ_2012OCT
SOME_TABLE_ABC_2012OCT
SOME_TABLE_LMN_2012OCT
SOME_TABLE_XYZ_2012NOV
SOME_TABLE_ABC_2012NOV
SOME_TABLE_LMN_2012NOV
I need to roll these all up into a single view named SOME_TABLE, with the data union all'd together. It must be dynamic because there can be new 3 char codes and obviously, monthly new tables being created.
Ideally I'd like a SP that creates a view named SOME_TABLE, then I can query off of SOME_TABLE to do the work that I need on it (scheduled ETL into a sql server 2012 data warehouse). I know that I could just have the SP return a cursor, but creating the view gives me flexibility to make it an indexed view if I need for performance, and ease of use from other ETL tools.
I figure on querying sys.tables (or whatever it is), and working from there to build up a sql statement for a create view.
Any other bright ideas on how to approach this?
You can use this query batch to create the view. But you need to keep updating it.
declare #v nvarchar(max) =
(
select stuff((
select cast(' union all select * from ' as nvarchar(max)) + quotename(name)
from sys.tables
where name like 'SOME\_TABLE\____\_[0-9][0-9][0-9][0-9][a-Z][a-Z][a-Z]' escape '\'
for xml path('a'), type
).value('.','nvarchar(max)'),1,11,'')
);
set #v = 'CREATE VIEW SOME_TABLE AS ' + #v;
exec (#v);
This is a stored proc that takes the base table name, and creates a view for it (I wrapped the above code into a proc that takes a parameter)
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE spCreateUnionedView
#BaseTableName varchar(100)
AS
BEGIN
SET NOCOUNT ON;
declare #v nvarchar(max) =
(
select stuff((
select cast(' union all select * from ' as nvarchar(max)) + quotename(name)
from sys.tables
where name like replace(#BaseTableName, '_', '\_') + '\____\_[0-9][0-9][0-9][0-9][a-Z][a-Z][a-Z]' escape '\'
for xml path('a'), type
).value('.','nvarchar(max)'),1,11,'')
);
declare #s nvarchar(max) = 'DROP VIEW ' + #BaseTableName;
exec (#s);
set #v = 'CREATE VIEW ' + #BaseTableName + ' AS ' + #v;
exec (#v);
END
GO