Move tables from one database to another with primary key - sql

I want to move the tables from one database to another, using dynamic SQL queries. I have a stored procedure to move the tables, but it is not moving the primary keys with table
This is my code:
set #cSQL='Select Name from '+#cSDBName+'.sys.tables where Type=''U'''
Insert into #t1Table
exec (#cSQL)
while((select count(tName) from #t1Table)>0)
begin
select top 1 #cName=tName from #t1Table
set #cSQL='Select * into '+#cDBName+'.dbo.'+#cName+' from '+#cSDBName+'.dbo.'+#cName +' where 1=2'
exec(#cSQL)
delete from #t1Table where tName=#cName
end
Here #cSDBName is the name of the source database and #cSQL is the SQL statement.
But this process won't move the primary key
Can anyone help me with this?

See this...
Clones an existing table to another table (without data)
Optionally drops and re-creates target table
Copies:
* Structure
* Primary key
* Indexes (including ASC/DESC, included columns, filters)
* Constraints (and unique constraints)
DOES NOT copy:
* Triggers
* File groups
* Probably a lot of other things
Note: Assumes that you name (unique) constraints with the table name in it (in order to not duplicate constraint names)
*/
SET NOCOUNT ON;
BEGIN TRANSACTION
--drop the table
if EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = #DestinationSchema AND TABLE_NAME = #DestinationTable)
BEGIN
if #RecreateIfExists = 1
BEGIN
exec('DROP TABLE [' + #DestinationSchema + '].[' + #DestinationTable + ']')
END
ELSE
RETURN
END
--create the table
exec('SELECT TOP (0) * INTO [' + #DestinationSchema + '].[' + #DestinationTable + '] FROM [' + #SourceSchema + '].[' + #SourceTable + ']')
DECLARE #PKSchema nvarchar(255), #PKName nvarchar(255)
SELECT TOP 1 #PKSchema = CONSTRAINT_SCHEMA, #PKName = CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA = #SourceSchema AND TABLE_NAME = #SourceTable AND CONSTRAINT_TYPE = 'PRIMARY KEY'
--create primary key
IF NOT #PKSchema IS NULL AND NOT #PKName IS NULL
BEGIN
DECLARE #PKColumns nvarchar(MAX)
SET #PKColumns = ''
SELECT #PKColumns = #PKColumns + '[' + COLUMN_NAME + '],'
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
where TABLE_NAME = #SourceTable and TABLE_SCHEMA = #SourceSchema AND CONSTRAINT_SCHEMA = #PKSchema AND CONSTRAINT_NAME= #PKName
ORDER BY ORDINAL_POSITION
SET #PKColumns = LEFT(#PKColumns, LEN(#PKColumns) - 1)
exec('ALTER TABLE [' + #DestinationSchema + '].[' + #DestinationTable + '] ADD CONSTRAINT [PK_' + #DestinationTable + '] PRIMARY KEY CLUSTERED (' + #PKColumns + ')');
END
--create other indexes
DECLARE #IndexId int, #IndexName nvarchar(255), #IsUnique bit, #IsUniqueConstraint bit, #FilterDefinition nvarchar(max)
DECLARE indexcursor CURSOR FOR
SELECT index_id, name, is_unique, is_unique_constraint, filter_definition FROM sys.indexes WHERE type = 2 and object_id = object_id('[' + #SourceSchema + '].[' + #SourceTable + ']')
OPEN indexcursor;
FETCH NEXT FROM indexcursor INTO #IndexId, #IndexName, #IsUnique, #IsUniqueConstraint, #FilterDefinition;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #Unique nvarchar(255)
SET #Unique = CASE WHEN #IsUnique = 1 THEN ' UNIQUE ' ELSE '' END
DECLARE #KeyColumns nvarchar(max), #IncludedColumns nvarchar(max)
SET #KeyColumns = ''
SET #IncludedColumns = ''
select #KeyColumns = #KeyColumns + '[' + c.name + '] ' + CASE WHEN is_descending_key = 1 THEN 'DESC' ELSE 'ASC' END + ',' from sys.index_columns ic
inner join sys.columns c ON c.object_id = ic.object_id and c.column_id = ic.column_id
where index_id = #IndexId and ic.object_id = object_id('[' + #SourceSchema + '].[' + #SourceTable + ']') and key_ordinal > 0
order by index_column_id
select #IncludedColumns = #IncludedColumns + '[' + c.name + '],' from sys.index_columns ic
inner join sys.columns c ON c.object_id = ic.object_id and c.column_id = ic.column_id
where index_id = #IndexId and ic.object_id = object_id('[' + #SourceSchema + '].[' + #SourceTable + ']') and key_ordinal = 0
order by index_column_id
IF LEN(#KeyColumns) > 0
SET #KeyColumns = LEFT(#KeyColumns, LEN(#KeyColumns) - 1)
IF LEN(#IncludedColumns) > 0
BEGIN
SET #IncludedColumns = ' INCLUDE (' + LEFT(#IncludedColumns, LEN(#IncludedColumns) - 1) + ')'
END
IF #FilterDefinition IS NULL
SET #FilterDefinition = ''
ELSE
SET #FilterDefinition = 'WHERE ' + #FilterDefinition + ' '
if #IsUniqueConstraint = 0
exec('CREATE ' + #Unique + ' NONCLUSTERED INDEX [' + #IndexName + '] ON [' + #DestinationSchema + '].[' + #DestinationTable + '] (' + #KeyColumns + ')' + #IncludedColumns + #FilterDefinition)
ELSE
BEGIN
SET #IndexName = REPLACE(#IndexName, #SourceTable, #DestinationTable)
exec('ALTER TABLE [' + #DestinationSchema + '].[' + #DestinationTable + '] ADD CONSTRAINT [' + #IndexName + '] UNIQUE NONCLUSTERED (' + #KeyColumns + ')');
END
FETCH NEXT FROM indexcursor INTO #IndexId, #IndexName, #IsUnique, #IsUniqueConstraint, #FilterDefinition;
END;
CLOSE indexcursor;
DEALLOCATE indexcursor;
--create constraints
DECLARE #ConstraintName nvarchar(max), #CheckClause nvarchar(max)
DECLARE constraintcursor CURSOR FOR
SELECT REPLACE(c.CONSTRAINT_NAME, #SourceTable, #DestinationTable), CHECK_CLAUSE from INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE t
INNER JOIN INFORMATION_SCHEMA.CHECK_CONSTRAINTS c ON c.CONSTRAINT_SCHEMA = TABLE_SCHEMA AND c.CONSTRAINT_NAME = t.CONSTRAINT_NAME
WHERE TABLE_SCHEMA = #SourceSchema AND TABLE_NAME = #SourceTable
OPEN constraintcursor;
FETCH NEXT FROM constraintcursor INTO #ConstraintName, #CheckClause;
WHILE ##FETCH_STATUS = 0
BEGIN
exec('ALTER TABLE [' + #DestinationSchema + '].[' + #DestinationTable + '] WITH CHECK ADD CONSTRAINT [' + #ConstraintName + '] CHECK ' + #CheckClause)
exec('ALTER TABLE [' + #DestinationSchema + '].[' + #DestinationTable + '] CHECK CONSTRAINT [' + #ConstraintName + ']')
FETCH NEXT FROM constraintcursor INTO #ConstraintName, #CheckClause;
END;
CLOSE constraintcursor;
DEALLOCATE constraintcursor;
COMMIT TRANSACTION
END

Well, the query you've written only moves the data. You've not specified the primary keys anywhere.
You'll need to either create the tables via your script, or alter the table via your script to define the primary keys.

Related

SQL Server After Insert/Update/Delete Trigger - data type error

I'm trying to create a trigger that automatically fills an audit table when a change is made in my main table.
The trigger mainly taken from here: https://newbedev.com/log-record-changes-in-sql-server-in-an-audit-table is:
ALTER TRIGGER [dbo].[TR_Price_AUDIT] ON [dbo].[PriceList] FOR INSERT, UPDATE, DELETE
AS
DECLARE #bit INT,
#field INT,
#maxfield INT,
#char INT,
#fieldname VARCHAR(128),
#TableName VARCHAR(128),
#PKCols VARCHAR(1000),
#sql VARCHAR(2000),
#UpdateDate VARCHAR(21),
#UserName VARCHAR(128),
#Type CHAR(1),
#PKSelect VARCHAR(1000),
#lastAuditPK BIGINT,
#AuditGroupPK VARCHAR(2000)
--You will need to change #TableName to match the table to be audited.
SELECT #TableName = 'PriceList'
SELECT #UserName = SYSTEM_USER,
#UpdateDate = CONVERT(NVARCHAR(30), GETDATE(), 126)
SELECT #AuditGroupPK = (SELECT top 1 Id FROM [Audit].[dbo].[PriceAudit] Order by Id desc) + 1
-- SELECT #AuditGroupPK = convert(int,3)
-- Action
IF EXISTS (
SELECT *
FROM INSERTED
)
IF EXISTS (
SELECT *
FROM DELETED
)
SELECT #Type = 'U'
ELSE
SELECT #Type = 'I'
ELSE
SELECT #Type = 'D'
-- get list of columns
SELECT * INTO #ins
FROM INSERTED
SELECT * INTO #del
FROM DELETED
-- Get primary key columns for full outer join
SELECT #PKCols = COALESCE(#PKCols + ' and', ' on')
+ ' i.[' + c.COLUMN_NAME + '] = d.[' + c.COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE pk.TABLE_NAME = #TableName
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
-- Get primary key select for insert
SELECT #PKSelect = COALESCE(#PKSelect + '+', '')
+ '''<[' + COLUMN_NAME
+ ']=''+convert(varchar(100),
coalesce(i.[' + COLUMN_NAME + '],d.[' + COLUMN_NAME + ']))+''>'''
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE pk.TABLE_NAME = #TableName
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
-- Get primary key select for insert
SELECT #PKSelect = 'convert(varchar(100),
coalesce(i.[' + COLUMN_NAME + '],d.[' + COLUMN_NAME + ']))'
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE pk.TABLE_NAME = #TableName
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
IF #PKCols IS NULL
BEGIN
RAISERROR('no PK on table %s', 16, -1, #TableName)
RETURN
END
SELECT #field = 0,
-- #maxfield = MAX(COLUMN_NAME)
#maxfield = -- FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #TableName
MAX(
COLUMNPROPERTY(
OBJECT_ID(TABLE_SCHEMA + '.' + #TableName),
COLUMN_NAME,
'ColumnID'
)
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName
WHILE #field < #maxfield
BEGIN
SELECT #field = MIN(
COLUMNPROPERTY(
OBJECT_ID(TABLE_SCHEMA + '.' + #TableName),
COLUMN_NAME,
'ColumnID'
)
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName
AND COLUMNPROPERTY(
OBJECT_ID(TABLE_SCHEMA + '.' + #TableName),
COLUMN_NAME,
'ColumnID'
) > #field
SELECT #bit = (#field - 1)% 8 + 1
SELECT #bit = POWER(2, #bit - 1)
SELECT #char = ((#field - 1) / 8) + 1
IF SUBSTRING(COLUMNS_UPDATED(), #char, 1) & #bit > 0
OR #Type IN ('I', 'D')
BEGIN
SELECT #fieldname = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName
AND COLUMNPROPERTY(
OBJECT_ID(TABLE_SCHEMA + '.' + #TableName),
COLUMN_NAME,
'ColumnID'
) = #field
SELECT #sql =
'
insert into [Audit].[dbo].[PriceAudit] ( Type,
TableName,
PK,
FieldName,
OldValue,
NewValue,
UpdateDate,
UserName, GroupId)
select ''' + #Type + ''','''
+ #TableName + ''',' + #PKSelect
+ ',''' + #fieldname + ''''
+ ',CAST(CAST(d.' + #fieldname + ' AS nvarchar(1000)) AS varchar(1000))'
+ ',CAST(CAST(i.' + #fieldname + ' AS nvarchar(1000)) AS varchar(1000))'
+ ',''' + #UpdateDate + ''''
+ ',''' + #UserName + ''''
+ ',' + #AuditGroupPK + ''
+ ' from #ins i full outer join #del d'
+ #PKCols
+ ' where i.' + #fieldname + ' <> d.' + #fieldname
+ ' or (i.' + #fieldname + ' is null and d.'
+ #fieldname
+ ' is not null)'
+ ' or (i.' + #fieldname + ' is not null and d.'
+ #fieldname
+ ' is null)'
EXEC (#sql)
END
END
It mainly works, but when the field contains data like '44.154214' it throws the error:
table Conversion failed when converting the varchar value '44.154214' to data type int.
I'm not sure why it's trying to set it to be an int. I want it to be a varchar.
I've tried casting it to varchar but that hasn't helped. Is there anything I can do to make this work?

Insert missing rows for all the tables from one database into another database

I have 2 databases with same set of tables. Total number of rows in each of the tables differ between the two databases. I have to insert the missing rows for all the tables from one database into another.
Is there a way I could do it all at one shot?
I can do it manually for each table with the below query:
Considering id as the unique column:
insert into databasename.dbo.tablename
select *
from datababasename2.dbo.tablename2
where id not in (select id from databasename.dbo.tablename)
I want to do this for all the tables in the database. Looking for ways to do it dynamically.
To transfer 1000's of rows simply delete and reload. This is much simpler than trying to implement differential. Here's some code, most of which is error handling. This does not allow for a table with an identity. Let me know if this is the case.
BEGIN TRY
BEGIN TRAN
DELETE TargetDB.dbo.TargetTable;
INSERT INTO TargetDB.dbo.TargetTable (column1,column2,column3)
SELECT column1,column2,column3 FROM SourceDB.dbo.SourceTable;
COMMIT TRAN
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK
DECLARE #ErrMsg nvarchar(4000), #ErrSeverity int
SELECT #ErrMsg = ERROR_MESSAGE(),
#ErrSeverity = ERROR_SEVERITY()
RAISERROR(#ErrMsg, #ErrSeverity, 1)
END CATCH
(commit/catch pattern lifted from here: https://web.archive.org/web/20211020150034/http://www.4guysfromrolla.com/webtech/041906-1.shtml)
You can achieve this using a stored procedure that contains SQL Dynamic queries:
CREATE PROCEDURE SyncDatabases
(
#p_strSourceDatabase Varchar(50),
#p_strDestinationDatabase Varchar(50),
#p_Identity Bit --If your tables contains Identity columns
) AS
BEGIN
DECLARE #strQuery VARCHAR(MAX)
CREATE TABLE #TblTemp(TABLE_SCHEMA VARCHAR(50), TABLE_NAME VARCHAR(50), [COLUMNS] VARCHAR(MAX))
SET #strQuery = 'INSERT INTO #TblTemp (TABLE_SCHEMA , TABLE_NAME, COLUMNS)
SELECT DISTINCT T1.TABLE_SCHEMA,T1.TABLE_NAME, (SELECT ''['' + COLUMN_NAME + ''],'' FROM [' + #p_strSourceDatabase + '].INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = T1.TABLE_NAME AND TABLE_SCHEMA = T1.TABLE_SCHEMA FOR XML PATH('''')) AS [COLUMNS]
FROM [' + #p_strSourceDatabase + '].INFORMATION_SCHEMA.COLUMNS AS T1
INNER JOIN [' + #p_strDestinationDatabase + '].INFORMATION_SCHEMA.COLUMNS AS T2
ON T1.TABLE_SCHEMA = T2.TABLE_SCHEMA
AND T1.TABLE_NAME = T2.TABLE_NAME
AND T1.COLUMN_NAME = T2.COLUMN_NAME'
EXEC(#strQuery)
SET #strQuery = ''
SELECT #strQuery = #strQuery + CASE WHEN #p_Identity = 1 THEN 'SET IDENTITY_INSERT [' + #p_strDestinationDatabase + '].[' + T1.TABLE_SCHEMA + '].[' + T1.TABLE_NAME + '] ON ' ELSE '' END + ' INSERT INTO [' + #p_strDestinationDatabase + '].[' + T1.TABLE_SCHEMA + '].[' + T1.TABLE_NAME + '] (' + LEFT(T1.COLUMNS,LEN(T1.COLUMNS) - 1) + ')
SELECT ' + LEFT(T1.COLUMNS,LEN(T1.COLUMNS) - 1) + ' FROM [' + #p_strSourceDatabase + '].[' + T1.TABLE_SCHEMA + '].[' + T1.TABLE_NAME + '] AS T1
WHERE NOT EXISTS (SELECT 1 FROM [' + #p_strDestinationDatabase + '].[' + T1.TABLE_SCHEMA + '].[' + T1.TABLE_NAME + '] AS T2 WHERE T1.ID = T2.ID);
'
FROM #TblTemp AS T1
EXEC(#strQuery)
DROP TABLE #TblTemp
END

Create indexes for all tables in database?

I know I can index a column in a table with the command:
CREATE UNIQUE INDEX index_name
ON table_name (column_name)
However, I have a database of 250 schemas with 10 tables each. How can I, for each table, check if a column exists, and then create an index for it (if it does exist)?
I am using SQL Server 2012.
A small variation on Banana's answer is to use INFORMATION_SCHEMA.COLUMNS to grab the final list of tables directly:
-- Define column to index.
DECLARE #coltoindex VARCHAR(20), #indexoptions VARCHAR(30)
SET #coltoindex = 'Id'
SET #indexoptions = 'UNIQUE'
--USE database_name
--IF OBJECT_ID('tempdb..#tables') IS NOT NULL DROP TABLE #tables
SELECT table_schema, table_name INTO #tables FROM information_schema.columns
where COLUMN_NAME = #coltoindex
DECLARE #schema VARCHAR(30), #table VARCHAR(20), #sqlCommand varchar(1000)
WHILE (SELECT COUNT(*) FROM #tables) > 0
BEGIN
SELECT TOP 1 #schema = table_schema, #table = table_name FROM #tables
SET #sqlCommand = '
CREATE ' + #indexoptions + ' INDEX
idx_' + #schema + '_' + #table + '_' + #coltoindex + '
ON ' + #schema + '.' + #table + ' (' + #coltoindex + ')'
-- print #sqlCommand
EXEC (#sqlCommand)
DELETE FROM #tables WHERE table_schema = #schema AND table_name = #table
END
A simple way of achieving what you want, is to loop over all tables through information_schema.tables and then create the index if the row exists in that table:
-- Define column to index.
DECLARE #coltoindex VARCHAR(20), #indexoptions VARCHAR(30)
SET #coltoindex = 'Id'
SET #indexoptions = 'UNIQUE'
USE database_name
--IF OBJECT_ID('tempdb..#tables') IS NOT NULL DROP TABLE #tables
SELECT table_schema, table_name INTO #tables FROM information_schema.tables
DECLARE #schema VARCHAR(30), #table VARCHAR(20), #sqlCommand varchar(1000)
WHILE (SELECT COUNT(*) FROM #tables) > 0
BEGIN
SELECT TOP 1 #schema = table_schema, #table = table_name FROM #tables
SET #sqlCommand = '
IF EXISTS(SELECT * FROM sys.columns
WHERE [name] = N''' + #coltoindex + '''
AND [object_id] = OBJECT_ID(N''' + #schema + '.' + #table + '''))
BEGIN
CREATE ' + #indexoptions + ' INDEX
idx_' + #schema + '_' + #table + '_' + #coltoindex + '
ON ' + #schema + '.' + #table + ' (' + #coltoindex + ')
END'
EXEC (#sqlCommand)
DELETE FROM #tables WHERE table_schema = #schema AND table_name = #table
END

How to remove SQL Azure Data Sync objects manually

Having given up on SQL Azure Data Sync for synchronizing data between two SQL Azure databases, how can I remove all the DataSync related objects (tables, triggers etc)?
E.g:
DataSync.<table>_dss_tracking
DataSync.schema_info_dss
DataSync.scope_config_dss
DataSync.scope_info_dss
And all the other objects? Is there a script that can be run?
There is an article on msgooroo.com:
https://msgooroo.com/GoorooTHINK/Article/15141/Removing-SQL-Azure-Sync-objects-manually/5215
Essentially the script is as follows:
-- Triggers
DECLARE #TRIGGERS_SQL VARCHAR(MAX) = (
SELECT
'DROP TRIGGER [' + SCHEMA_NAME(so.uid) + '].[' + [so].[name] + '] '
FROM sysobjects AS [so]
INNER JOIN sysobjects AS so2 ON so.parent_obj = so2.Id
WHERE [so].[type] = 'TR'
AND [so].name LIKE '%_dss_%_trigger'
FOR XML PATH ('')
)
PRINT #TRIGGERS_SQL
IF LEN(#TRIGGERS_SQL) > 0
BEGIN
EXEC (#TRIGGERS_SQL)
END
-- Tables
DECLARE #TABLES_SQL VARCHAR(MAX) = (
SELECT
'DROP TABLE [' + table_schema + '].[' + table_name + '] '
FROM
information_schema.tables where table_schema = 'DataSync'
FOR XML PATH ('')
)
PRINT #TABLES_SQL
IF LEN(#TABLES_SQL) > 0
BEGIN
EXEC (#TABLES_SQL)
END
-- Stored Procedures
DECLARE #PROC_SQL VARCHAR(MAX) = (
SELECT 'DROP PROCEDURE [' + routine_schema + '].[' + routine_name + '] '
FROM INFORMATION_SCHEMA.ROUTINES where ROUTINE_SCHEMA = 'DataSync' and routine_type = 'PROCEDURE'
FOR XML PATH ('')
)
PRINT #PROC_SQL
IF LEN(#PROC_SQL) > 0
BEGIN
EXEC (#PROC_SQL)
END
-- Types
DECLARE #TYPE_SQL VARCHAR(MAX) = (
SELECT
'DROP TYPE [' + SCHEMA_NAME(so.uid) + '].[' + [so].[name] + '] '
FROM systypes AS [so]
where [so].name LIKE '%_dss_bulktype%'
AND SCHEMA_NAME(so.uid) = 'Datasync'
FOR XML PATH ('')
)
PRINT #TYPE_SQL
IF LEN(#TYPE_SQL) > 0
BEGIN
EXEC (#TYPE_SQL)
END
-- Schema
DROP SCHEMA DataSync
I recently ran into this issue and while the script in the accepted answer did remove the DataSync schema, it did not remove the dss or TaskHosting schemas nor the symmetric key objects that were preventing me from exporting my database.
I ended up needing to contact Azure support to get everything removed. Here is the script that they gave me:
declare #n char(1)
set #n = char(10)
declare #triggers nvarchar(max)
declare #procedures nvarchar(max)
declare #constraints nvarchar(max)
declare #views nvarchar(max)
declare #FKs nvarchar(max)
declare #tables nvarchar(max)
declare #udt nvarchar(max)
-- triggers
select #triggers = isnull( #triggers + #n, '' ) + 'drop trigger [' + schema_name(schema_id) + '].[' + name + ']'
from sys.objects
where type in ( 'TR') and name like '%_dss_%'
-- procedures
select #procedures = isnull( #procedures + #n, '' ) + 'drop procedure [' + schema_name(schema_id) + '].[' + name + ']'
from sys.procedures
where schema_name(schema_id) = 'dss' or schema_name(schema_id) = 'TaskHosting' or schema_name(schema_id) = 'DataSync'
-- check constraints
select #constraints = isnull( #constraints + #n, '' ) + 'alter table [' + schema_name(schema_id) + '].[' + object_name( parent_object_id ) + '] drop constraint [' + name + ']'
from sys.check_constraints
where schema_name(schema_id) = 'dss' or schema_name(schema_id) = 'TaskHosting' or schema_name(schema_id) = 'DataSync'
-- views
select #views = isnull( #views + #n, '' ) + 'drop view [' + schema_name(schema_id) + '].[' + name + ']'
from sys.views
where schema_name(schema_id) = 'dss' or schema_name(schema_id) = 'TaskHosting' or schema_name(schema_id) = 'DataSync'
-- foreign keys
select #FKs = isnull( #FKs + #n, '' ) + 'alter table [' + schema_name(schema_id) + '].[' + object_name( parent_object_id ) + '] drop constraint [' + name + ']'
from sys.foreign_keys
where schema_name(schema_id) = 'dss' or schema_name(schema_id) = 'TaskHosting' or schema_name(schema_id) = 'DataSync'
-- tables
select #tables = isnull( #tables + #n, '' ) + 'drop table [' + schema_name(schema_id) + '].[' + name + ']'
from sys.tables
where schema_name(schema_id) = 'dss' or schema_name(schema_id) = 'TaskHosting' or schema_name(schema_id) = 'DataSync'
-- user defined types
select #udt = isnull( #udt + #n, '' ) +
'drop type [' + schema_name(schema_id) + '].[' + name + ']'
from sys.types
where is_user_defined = 1
and schema_name(schema_id) = 'dss' or schema_name(schema_id) = 'TaskHosting' or schema_name(schema_id) = 'DataSync'
order by system_type_id desc
print #triggers
print #procedures
print #constraints
print #views
print #FKs
print #tables
print #udt
exec sp_executesql #triggers
exec sp_executesql #procedures
exec sp_executesql #constraints
exec sp_executesql #FKs
exec sp_executesql #views
exec sp_executesql #tables
exec sp_executesql #udt
GO
declare #n char(1)
set #n = char(10)
declare #functions nvarchar(max)
-- functions
select #functions = isnull( #functions + #n, '' ) + 'drop function [' + schema_name(schema_id) + '].[' + name + ']'
from sys.objects
where type in ( 'FN', 'IF', 'TF' )
and schema_name(schema_id) = 'dss' or schema_name(schema_id) = 'TaskHosting' or schema_name(schema_id) = 'DataSync'
print #functions
exec sp_executesql #functions
GO
--update
DROP SCHEMA IF EXISTS [dss]
GO
DROP SCHEMA IF EXISTS [TaskHosting]
GO
DROP SCHEMA IF EXISTS [DataSync]
GO
DROP USER IF EXISTS [##MS_SyncAccount##]
GO
DROP ROLE IF EXISTS [DataSync_admin]
GO
DROP ROLE IF EXISTS [DataSync_executor]
GO
DROP ROLE IF EXISTS [DataSync_reader]
GO
declare #n char(1)
set #n = char(10)
--symmetric_keys
declare #symmetric_keys nvarchar(max)
select #symmetric_keys = isnull( #symmetric_keys + #n, '' ) + 'drop symmetric key [' + name + ']'
from sys.symmetric_keys
where name like 'DataSyncEncryptionKey%'
print #symmetric_keys
exec sp_executesql #symmetric_keys
-- certificates
declare #certificates nvarchar(max)
select #certificates = isnull( #certificates + #n, '' ) + 'drop certificate [' + name + ']'
from sys.certificates
where name like 'DataSyncEncryptionCertificate%'
print #certificates
exec sp_executesql #certificates
GO
print 'Data Sync clean up finished'
After trying a few queries, this is the only one that worked:
declare #n char(1)
set #n = char(10)
declare #triggers nvarchar(max)
declare #procedures nvarchar(max)
declare #constraints nvarchar(max)
declare #FKs nvarchar(max)
declare #tables nvarchar(max)
declare #udt nvarchar(max)
-- triggers
select #triggers = isnull( #triggers + #n, '' ) + 'drop trigger [' + schema_name(schema_id) + '].[' + name + ']'
from sys.objects
where type in ( 'TR') and name like '%_dss_%'
-- procedures
select #procedures = isnull( #procedures + #n, '' ) + 'drop procedure [' + schema_name(schema_id) + '].[' + name + ']'
from sys.procedures
where schema_name(schema_id) = 'dss' or schema_name(schema_id) = 'TaskHosting' or schema_name(schema_id) = 'DataSync'
-- check constraints
select #constraints = isnull( #constraints + #n, '' ) + 'alter table [' + schema_name(schema_id) + '].[' + object_name( parent_object_id ) + '] drop constraint [' + name + ']'
from sys.check_constraints
where schema_name(schema_id) = 'dss' or schema_name(schema_id) = 'TaskHosting' or schema_name(schema_id) = 'DataSync'
-- foreign keys
select #FKs = isnull( #FKs + #n, '' ) + 'alter table [' + schema_name(schema_id) + '].[' + object_name( parent_object_id ) + '] drop constraint [' + name + ']'
from sys.foreign_keys
where schema_name(schema_id) = 'dss' or schema_name(schema_id) = 'TaskHosting' or schema_name(schema_id) = 'DataSync'
-- tables
select #tables = isnull( #tables + #n, '' ) + 'drop table [' + schema_name(schema_id) + '].[' + name + ']'
from sys.tables
where schema_name(schema_id) = 'dss' or schema_name(schema_id) = 'TaskHosting' or schema_name(schema_id) = 'DataSync'
-- user defined types
select #udt = isnull( #udt + #n, '' ) + 'drop type [' + schema_name(schema_id) + '].[' + name + ']'
from sys.types
where is_user_defined = 1
and schema_name(schema_id) = 'dss' or schema_name(schema_id) = 'TaskHosting' or schema_name(schema_id) = 'DataSync'
order by system_type_id desc
print #triggers
print #procedures
print #constraints
print #FKs
print #tables
print #udt
exec sp_executesql #triggers
exec sp_executesql #procedures
exec sp_executesql #constraints
exec sp_executesql #FKs
exec sp_executesql #tables
exec sp_executesql #udt
declare #functions nvarchar(max)
-- functions
select #functions = isnull( #functions + #n, '' ) + 'drop function [' + schema_name(schema_id) + '].[' + name + ']'
from sys.objects
where type in ( 'FN', 'IF', 'TF' )
and schema_name(schema_id) = 'dss' or schema_name(schema_id) = 'TaskHosting' or schema_name(schema_id) = 'DataSync'
print #functions
exec sp_executesql #functions
DROP SCHEMA IF EXISTS [dss]
DROP SCHEMA IF EXISTS [TaskHosting]
DROP SCHEMA IF EXISTS [DataSync]
DROP USER IF EXISTS [##MS_SyncAccount##]
DROP USER IF EXISTS [##MS_SyncResourceManager##]
DROP ROLE IF EXISTS [DataSync_admin]
DROP ROLE IF EXISTS [DataSync_executor]
DROP ROLE IF EXISTS [DataSync_reader]
--symmetric_keys
declare #symmetric_keys nvarchar(max)
select #symmetric_keys = isnull( #symmetric_keys + #n, '' ) + 'drop symmetric key [' + name + ']'
from sys.symmetric_keys
where name like 'DataSyncEncryptionKey%'
print #symmetric_keys
exec sp_executesql #symmetric_keys
-- certificates
declare #certificates nvarchar(max)
select #certificates = isnull( #certificates + #n, '' ) + 'drop certificate [' + name + ']'
from sys.certificates
where name like 'DataSyncEncryptionCertificate%'
print #certificates
exec sp_executesql #certificates
print 'Data Sync clean up finished'
Source: https://github.com/vitomaz-msft/DataSyncMetadataCleanup
Thanks vitomaz!
If your architecture between Azure and SQL Server is still in place - you can simply unregister from the SQL Data Sync Agent which will delete above objects for you.
Microsoft released this script a while ago. Handy if you need to remove a single table
declare #TableName nvarchar(max)
set #TableName = 'yourTableName'
--In case you wish to delete objects related to all the tables you can uncomment the following:
--set #TableName = ''
-- Generate the script to drop Data Sync tables
select 'drop table [DataSync].['+ st.name+ '];' from sys.tables as st join sys.schemas as ss on ss.schema_id = st.schema_id
where ss.name = 'DataSync' and st.name like '%' + #TableName + '_dss_%'
-- Generate the script to drop Data Sync stored procedures
select 'drop procedure [DataSync].['+ sp.name+ '];' from sys.procedures as sp join sys.schemas as ss on ss.schema_id = sp.schema_id
where ss.name = 'DataSync' and sp.name like '%' + #TableName + '_dss_%'
-- Generate the script to delete Data Sync triggers
select 'drop trigger [' + schema_name(schema_id) + '].[' + name + ']'
from sys.objects where type = 'TR' and name like '%' + #TableName + '_dss_%'
-- Generate the script to delete Data Sync-related udtt
select 'drop type [DataSync].['+ st.name+ '];' from sys.types as st join sys.schemas as ss on st.schema_id = ss.schema_id
where ss.name = 'DataSync' and st.name like '%' + #TableName + '_dss_%'
If you have sync setup on an on premise SQL Server, un-registering the database from the Azure Sync Agent interface will do the necessary cleanup.

Ignore Two Columns in Update Trigger

I am using the code below in a trigger. I have two columns that are updated by a windows service every 60 minutes in the table I am monitoring. How can I ignore the two columns from writing to the audit table.
ALTER trigger [dbo].[tMonitors_ChangeTracking] on [dbo].[tMonitors] for insert, update, delete
as
declare #bit int,
#field int,
#maxfield int,
#char int,
#fieldname varchar(128),
#TableName varchar(128),
#PKCols varchar(1000),
#sql varchar(2000),
#UpdateDate varchar(21),
#UserName varchar(128),
#Type char(1),
#PKFieldSelect varchar(1000),
#PKValueSelect varchar(1000)
select #TableName = 'tMonitors'
-- date and user
select #UserName = system_user ,
#UpdateDate = convert(varchar(8), getdate(), 112) + ' ' + convert(varchar(12), getdate(), 114)
-- Action
if exists (select * from inserted)
if exists (select * from deleted)
select #Type = 'U'
else
select #Type = 'I'
else
select #Type = 'D'
-- get list of columns
select * into #ins from inserted
select * into #del from deleted
-- Get primary key columns for full outer join
select #PKCols = coalesce(#PKCols + ' and', ' on') + ' i.' + c.COLUMN_NAME + ' = d.' + c.COLUMN_NAME
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
where pk.TABLE_NAME = #TableName
and CONSTRAINT_TYPE = 'PRIMARY KEY'
and c.TABLE_NAME = pk.TABLE_NAME
and c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
-- Get primary key fields select for insert
select #PKFieldSelect = coalesce(#PKFieldSelect+'+','') + '''' + COLUMN_NAME + ''''
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
where pk.TABLE_NAME = #TableName
and CONSTRAINT_TYPE = 'PRIMARY KEY'
and c.TABLE_NAME = pk.TABLE_NAME
and c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
select #PKValueSelect = coalesce(#PKValueSelect+'+','') + 'convert(varchar(100), coalesce(i.' + COLUMN_NAME + ',d.' + COLUMN_NAME + '))'
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
where pk.TABLE_NAME = #TableName
and CONSTRAINT_TYPE = 'PRIMARY KEY'
and c.TABLE_NAME = pk.TABLE_NAME
and c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
if #PKCols is null
begin
raiserror('no PK on table %s', 16, -1, #TableName)
return
end
select #field = 0, #maxfield = max(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = #TableName
while #field < #maxfield
begin
select #field = min(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = #TableName and ORDINAL_POSITION > #field
select #bit = (#field - 1 )% 8 + 1
select #bit = power(2,#bit - 1)
select #char = ((#field - 1) / 8) + 1
if substring(COLUMNS_UPDATED(),#char, 1) & #bit > 0 or #Type in ('I','D')
begin
select #fieldname = COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = #TableName and ORDINAL_POSITION = #field
select #sql = 'insert tMonitors_Audit (Type, TableName, PrimaryKeyField, PrimaryKeyValue, FieldName, OldValue, NewValue, UpdateDate, UserName)'
select #sql = #sql + ' select ''' + #Type + ''''
select #sql = #sql + ',''' + #TableName + ''''
select #sql = #sql + ',' + #PKFieldSelect
select #sql = #sql + ',' + #PKValueSelect
select #sql = #sql + ',''' + #fieldname + ''''
select #sql = #sql + ',convert(varchar(1000),d.' + #fieldname + ')'
select #sql = #sql + ',convert(varchar(1000),i.' + #fieldname + ')'
select #sql = #sql + ',''' + #UpdateDate + ''''
select #sql = #sql + ',''' + #UserName + ''''
select #sql = #sql + ' from #ins i full outer join #del d'
select #sql = #sql + #PKCols
select #sql = #sql + ' where i.' + #fieldname + ' <> d.' + #fieldname
select #sql = #sql + ' or (i.' + #fieldname + ' is null and d.' + #fieldname + ' is not null)'
select #sql = #sql + ' or (i.' + #fieldname + ' is not null and d.' + #fieldname + ' is null)'
exec (#sql)
end
end
The simple approach, assuming these columns to ignore are only updated during this hourly process:
IF NOT (UPDATE(col_to_ignore_1) AND UPDATE(col_to_ignore_2))
BEGIN
...
EXEC(#sql);
END
Otherwise you can build a similar list based on INFORMATION_SCHEMA.COLUMNS, so that the logging only happens when at least one of the other columns is updated, that would end up like this:
IF (UPDATE(col_to_audit_1) OR UPDATE(col_to_audit_2) ... )
BEGIN
...
EXEC(#sql);
END
It is not clear from your question whether you want to ignore these two columns always, or only when this hourly process runs. Perhaps another idea is to use a transaction and disable the trigger for this update... it will obviously make the trigger much less complicated.
You can specify which columns you want to pay attention to by using the "UPDATE(column_name)" syntax, like so:
CREATE TRIGGER trigger_name ON tablename
FOR insert, update, delete
AS
SET NOCOUNT ON
IF ( UPDATE(Column1) OR UPDATE(Column2))
BEGIN
--your sql here
END
Other options are available at the official documentation.
You can access the complete list of columns changed using COLUMNS_UPDATED() and compare it to pre-defined bit patterns. For tables with many columns, calculating the bit positions can be easier than listing out UPDATED(every) OR UPDATED(other) OR UPDATED(column).
For example, for a table:
CREATE TABLE Users
(
UserID INT NOT NULL PRIMARY KEY IDENTITY,
Name nvarchar(255) NOT NULL,
EmailAddress nvarchar(255) NOT NULL,
LastPageViewDate datetime NULL,
GroupID INT NOT NULL
);
where you want to ignore updates to LastPageViewDate. You can determine the bitmask via:
SELECT name, column_id FROM sys.columns WHERE object_id = OBJECT_ID('dbo.Users')
name column_id
-------------------- -----------
UserID 1
Name 2
EmailAddress 3
LastPageViewDate 4
GroupID 5
The trigger can then check for the little-endian bitmask 0x08 ignoring trailing 0's:
CREATE TRIGGER dbo.TR_IUD_Users_LogEdit
ON dbo.Users
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
-- Ignore page view logging caused by
-- UPDATE Users SET LastPageViewDate = GETDATE() WHERE UserID = #UserID
-- Bit 4 == LastPageViewDate
IF COLUMNS_UPDATED() = 0x08 RETURN;
-- For forward compatibility, you can ignore unchanged new columns added
-- by RTRIM'ing the '0's (required since 0x08 != 0x0800)
--
--IF REPLACE(RTRIM(REPLACE(CONVERT(varchar(max), COLUMNS_UPDATED(), 2), '0', ' ')), ' ', '0') IN ('08')
-- RETURN;
/* Snipped trigger body */
END
GO