Update tables with same name different schemas - sql

Using SQL Server and T-SQL, how can I update ALL tables tables with a specific name but different schemas under the same database?
:Update:
The updates include adding/deleting/modifying columns as well as changing specific values of rows.
I want to be able to deploy changes to a table across all schemas. Using the SQL Server Management Studio table designer, when I do a change and save, it allows me to save a script that can be used to deploy those changes to a different table. I want to be able to use that script on all tables with that specific name across all schemas.
:Update 2:
There reason for this request is that I want to ensure that updating a specific table across multiple schemas is easy to do. In the future, my application will undoubtedly change and if I see that it is difficult or inefficient to update schemas then I will opt to use something else.
Below is what I tried:
DECLARE #update_sql NVARCHAR(max)
DECLARE #table_name VARCHAR(45)
DECLARE c_tables CURSOR FOR
SELECT t.table_name
FROM INFORMATION_SCHEMA.TABLES t
WHERE t.table_name = 'TestTable'
AND t.table_catalog = 'MyDataBase'
OPEN c_tables
FETCH c_tables INTO #table_name
WHILE ##Fetch_Status = 0
BEGIN
SET #update_sql = N'ALTER TABLE '+#table_name+' ADD ColumnThree nvarchar(50) NULL'
EXEC sp_executesql #update_sql
END
CLOSE c_tables
DEALLOCATE c_tables
Running this generates the following error:
Cannot find the object "TestTable" because it does not exist or you do not have permissions.
The table exists and I'am running under dbo which is the schema owner.
I also noticed the query takes sometime to run even with only 7 tables in the database and 3 schemas used on those tables. Would it be more efficient to just login with each schema's owner and run a generic script? Each schema owner would only have access to their respective schema and tables.

On SQL Server 2005+, you can use INFORMATION_SCHEMA.TABLES to get a list of tables within a database:
SELECT t.table_name,
t.table_schema
FROM INFORMATION_SCHEMA.TABLES t
WHERE t.table_name = 'Table_1'
AND t.table_catalog = 'your_database'
But you didn't specify what updating you need - DML or DDL...
Update
DECLARE #update_sql NVARCHAR(max)
DECLARE #table_name VARCHAR(45)
DECLARE c_tables CURSOR FOR
SELECT t.table_name
FROM INFORMATION_SCHEMA.TABLES t
WHERE t.table_name = 'Table_1'
AND t.table_catalog = 'your_database'
OPEN c_tables
FETCH c_tables INTO #table_name
WHILE ##Fetch_Status = 0
BEGIN
SET #update_sql = N'UPDATE #table_name SET ...'
EXEC sp_executesql #update_sql
SET #update_sql = N'ALTER TABLE #table_name ...'
EXEC sp_executesql #update_sql
END
CLOSE c_tables
DEALLOCATE c_tables

You can use sp_MSforeachtable if the action will be the same on all (I'd obviously put some pretty robust error handling and rollback facilities into the scripts first)
exec sp_MSforeachtable
'
if parsename(''?'',1) = ''TargetTableName''
begin
update ? set ColumnToUpdate=NewValue;
execute sp_rename N''?.newname'', N''obsoletename'', ''column'' ;
alter table ? add newcol int null;
alter table ? drop column oldcol;
end'

Related

Is there a way add auto increment in all tables from a specific database at once?

I am trying to add auto increment in all existing tables in a specific database, and I can do that going through the table design, flagging the identity option, but in this case I have to do it table per table, and there is a lot of tables. Is there a way to do that automatically?
Copied from my comments per request:
I don't believe you're going to find an automated option for doing this for multiple tables. The change script that SSMS creates when you do this in table designer is already doing a ton of work you'd have to recreate for any other solution. Frankly, I wouldn't trust myself to do it as correctly as SSMS.
However, if it were a large enough number of tables, I would create a completely new database with the corrected schema. Ensure that everything in the new database is present and correct. Then, set identity insert to on all tables in the new db, copy the data over, set all the identity inserts off, and then move the new db to the old db with DETACH/ATTACH or BACKUP/RESTORE. In other words, I'd literally rebuild the database from the ground up because old schema had been completely trashed. It would take a lot for me to decide to do that in a production system, however.
I'd only do the DETACH/ATTACH or BACKUP/RESTORE if I absolutely needed to change the database file names or database names. I'd actually prefer to just use the new database as a new database for the application. That would also mean I could swap back to the old database pretty quickly if I ran into trouble.
It can be done by using a 'cursor', but you need to have all the columns that you need to add auto increment to in the same name as ID
Declare #Table nvarchar(50), #script nvarchar(100)
DECLARE cur CURSOR FORWARD_ONLY READ_ONLY LOCAL FOR
SELECT TABLE_SCHEMA + '.' + TABLE_NAME as 'Table' FROM INFORMATION_SCHEMA.TABLES where TABLE_NAME not in ('sysdiagrams') -- You can exclude any table from this process by adding it on the where statement
OPEN cur
FETCH NEXT FROM cur INTO #Table
WHILE ##FETCH_STATUS = 0 BEGIN
-- The sql command to alter a Table and add Identity to it, you can change ID by any column in your tables
set #script = 'Alter Table '+ #Table +' ADD ID INT IDENTITY'
EXEC sp_executesql #script
FETCH NEXT FROM cur INTO #Table
END
CLOSE cur
DEALLOCATE cur
Edit 1 : According to what you asked for in the comment
Declare #Table nvarchar(50), #script nvarchar(100), #primarykey_name nvarchar(20)
DECLARE cur CURSOR FORWARD_ONLY READ_ONLY LOCAL FOR
SELECT TABLE_SCHEMA + '.' + TABLE_NAME as 'Table' FROM INFORMATION_SCHEMA.TABLES where TABLE_NAME not in ('sysdiagrams') -- You can exclude any table from this process by adding it here
OPEN cur
FETCH NEXT FROM cur INTO #Table
WHILE ##FETCH_STATUS = 0 BEGIN
-- Find Primary key for the current Table and set it to #primarykey_name
Set #primarykey_name = (SELECT c.NAME FROM sys.key_constraints kc INNER JOIN sys.index_columns ic ON kc.parent_object_id = ic.object_id and kc.unique_index_id = ic.index_id
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
WHERE kc.name='PK_'+ substring(#Table, 5, LEN(#Table)-4) and kc.type = 'PK')
-- The sql command to alter a Table and add Identity to the primarykey of each table
set #script = 'Alter Table '+ #Table +' ADD ' + #primarykey_name + ' INT IDENTITY'
print #script
--EXEC sp_executesql #script
FETCH NEXT FROM cur INTO #Table
END
CLOSE cur
DEALLOCATE cur

Copy SQL Server database for development but smaller

We have production database above 100Gig. I want to duplicate this database and give it to every developer to test its code, but the size is too large. Is there anyway I can backup just top 1000 rows with FK's and restore it to new DB? Or duplicate the DB first and delete all records from all tables, but keep 1000 rows with FK's or any other way to keep size below 5Gig.
I did search, but none of solutions were for tables having foreign keys.
Thanks,
Basheer
This the IDEA:
First:
Create new database:
Second:
Select small records only like:
select top 500 from allYourTables
then insert to each every table to your new Database Created.
Third:
Dump the new database and give to its every developer
Hope it helps:
Assuming that you have a new db_to_dev Database name and you are working to your current database:
This procedure will insert all the data from your working database, making sure that you had already a database created. db_to_dev:
Using Information_Schema you can select all your tables:
CREATE PROCEDURE PROC_TRANSFER_DATA #NUM_OF_RECORDS nvarchar(255) as
BEGIN
SET NOCOUNT ON;
DECLARE #message varchar(80), #tablename nvarchar(50);
Declare #sqlstmt nvarchar(255);
PRINT '-------- List of tables --------';
DECLARE Schema_cursor CURSOR FOR
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
OPEN Schema_cursor
FETCH NEXT FROM Schema_cursor INTO #tablename
IF ##FETCH_STATUS <> 0
PRINT ' <<None>>'
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #message = ' ' + #tablename
set #sqlstmt = 'select top ' + #NUM_OF_RECORDS + ' * into [db_to_dev].[dbo].['+ #tablename +'] from ' + #tablename;
EXEC sp_executesql #sqlstmt
PRINT #message
FETCH NEXT FROM Schema_cursor INTO #tablename
END
CLOSE Schema_cursor
DEALLOCATE Schema_cursor
END
To use:
With an option parameter:
EXEC PROC_TRANSFER_DATA '500'
Parameter value is depend on you if how many records you want to transfer into your new database db_to_dev.
This Stored Proc is tested.
Good luck
There are a number of projects on github which seek to do exactly that: make a subset that preserves referential integrity. Here is one such project:
https://github.com/18F/rdbms-subsetter

Drop databases with no tables

Is there a query which drops / deletes databases with no tables in them (deletes empty databases)?
Server is Microsoft SQL Server 2005
This should do it.
Tested on a lab machine and it dropped all databases with 0 user tables.
Note, however, that tables aren't the only things in a database, necessarily. There could be stored procedures, functions, etc that someone might still need.
NOTE THAT THIS IS A VERY DANGEROUS OPERATION, AS IT DROPS DATABASES. USE AT YOUR OWN RISK. I AM NOT RESPONSIBLE FOR DAMAGE YOU CAUSE.
USE [master];
DECLARE #name varchar(50);
DECLARE #innerQuery varchar(max);
DECLARE tableCursor CURSOR FOR SELECT name FROM sys.databases where owner_sid != 0x01;
OPEN tableCursor;
FETCH NEXT FROM tableCursor
INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #innerQuery = 'USE [' + #name + ']; IF (SELECT COUNT(*) FROM sys.objects WHERE type = ''U'') = 0
BEGIN
USE [master];
DROP DATABASE [' + #name + ']
END'
EXEC(#innerQuery)
FETCH NEXT FROM tableCursor INTO #name
END
CLOSE tableCursor;
DEALLOCATE tableCursor;
Note also that, if a database is in use, SQL Server will refuse to drop it. So, if there are other connections to a particular database that this tries to drop, the command will abort.
To avoid that problem, you can set the database in question to single-user mode.
The following script is the same as the above, except it also sets the target databases to single-user mode to kill active connections.
BE EVEN MORE CAREFUL WITH THIS, AS IT'S ESSENTIALLY THE NUCLEAR OPTION:
use [master];
DECLARE #name varchar(50);
DECLARE #innerQuery varchar(max);
DECLARE tableCursor CURSOR FOR SELECT name FROM sys.databases where owner_sid != 0x01;
OPEN tableCursor;
FETCH NEXT FROM tableCursor
INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #innerQuery =
'USE [' + #name + '];
IF (SELECT COUNT(*) FROM sys.objects WHERE type = ''U'') = 0
BEGIN
USE [master];
ALTER DATABASE [' + #name + '] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [' + #name + '];
END'
EXEC(#innerQuery)
FETCH NEXT FROM tableCursor INTO #name
END
CLOSE tableCursor;
DEALLOCATE tableCursor;
I think it is not possible (at least not with a TSQL command, might be a stored procedure somewhere). You would have to query sysobjects and abort if any found. (And you have to decide if you want to ignore some of the system objects like the design tables).
The script below will generate the needed DROP DATABASE script. You could tweak this to execute the statement too (in the master database context) but I suggest you review it first just in case.
EXEC sp_MSforeachdb N'
USE [?];
IF N''?'' NOT IN(N''master'', N''model'', N''msdb'', N''tempdb'')
BEGIN
IF NOT EXISTS(
SELECT *
FROM sys.tables
WHERE
OBJECTPROPERTYEX(object_id, ''IsMSShipped'') = 0
)
BEGIN
PRINT ''DROP DATABASE [?];'';
END;
END;';

Delete all table data in a set [DB].[audit].[tables]

So, I have a database with around 100 audit tables and I want to empty them out preferably in 1 sql query. The database has 2 sets of tables [audit] and [dbo]. I'm not even sure what I should be calling these groups of tables so finding any kind of results from google is proving difficult.
Any suggestions?
You can find all tables with a certain schema name like:
select name from sys.tables where schema_name(schema_id) = 'audit'
With a cursor, you iterate over those tables, and empty them using TRUNCATE TABLE:
use db
declare #query nvarchar(max)
declare #tablename nvarchar(max)
declare #curs cursor
set #curs = cursor for select name from sys.tables
where schema_name(schema_id) = 'audit'
open #curs
fetch next from #curs into #tablename
while ##FETCH_STATUS = 0
begin
set #query = N'truncate table audit.' + #tablename
exec sp_executesql #query
fetch next from #curs into #tablename
end
close #curs
deallocate #curs
If you want to delete the tables instead, use:
set #query = N'drop table audit.' + #tablename
You could also use the sp_msforeachtable stored procedure.
It lets you perform a query on each user table in the current DB.
For example the following will truncate all user tables in your DB
Use YourDB
Exec sp_msforeachtable 'TRUNCATE TABLE ?'
And this will truncate all user tables in the specified db that belong to the audit schema.
Use YourDB
Exec sp_msforeachtable #command1 = '
if (Select Object_Schema_name(object_id(''?''))) = ''dbo''
Begin
TRUNCATE TABLE ?
print ''truncated '' + ''?''
End
'
Also Here is a blog entry with some more uses for this stored procedure.

TSQL to clear a database's schema in sql-server?

I'd like to clear a database's schema on my SqlServer instance. What tsql should I use?
By schema I mean tables, constraints, etc. I want the result to be similar to if I created a new database, however I don't want to actually drop and create the database.
Why:
For those curious, I need to empty the schema without dropping because of the way the database is being isolated for unit tests. Before running my tests a snapshot of the database is saved. After each test runs, this snapshot is restored. I can only ensure consistent state across unit tests if I keep my db operations within the scope of the database. Dropping/Create the database is outside of the db's scope (its in the master's scope).
In this case, I need to assert that an expected thing happens when the schema is empty. Emptying the schema via sql keeps the testing methodology consistent: do basically whatever you want to the db, exercise it, restore it.
Raj More's answer got me started. I was hoping someone could short circuit the processes.
Figured I'd share what I ultimately came up with. This script creates a cursor to loop over the tables in the db's INFORMATION_SCHEMA. It does 3 passes over the tables dopping Foreign Keys, then Primary Keys, and finally the tables themselves. Its based on Raj More's idea and considers devio's comment.
-- Helper Procedure
CREATE PROC #DropConstraints
#tableSchema nvarchar(max),
#tableName nvarchar(max),
#constraintType nvarchar(20)
AS
BEGIN
DECLARE #cName nvarchar(max);
DECLARE constraint_cursor CURSOR FOR
SELECT CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE
CONSTRAINT_TYPE = #constraintType
AND TABLE_NAME = #tableName
AND TABLE_SCHEMA = #tableSchema
OPEN constraint_cursor
FETCH NEXT FROM constraint_cursor INTO #cName
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC ('ALTER TABLE ' + #tableSchema + '.' + #tableName + ' DROP CONSTRAINT ' + #cName);
FETCH NEXT FROM constraint_cursor INTO #cName
END
CLOSE constraint_cursor
DEALLOCATE constraint_cursor
END
GO
-- DROP DATABASE TABLES
BEGIN TRANSACTION
DECLARE #tableSchema varchar(max), #tableName varchar(max);
-- Setup Cursor for looping
DECLARE table_cursor SCROLL CURSOR FOR
SELECT TABLE_SCHEMA, TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
OPEN table_cursor
-- Drop Foreign Keys
FETCH NEXT FROM table_cursor INTO #tableSchema, #tableName
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC #DropConstraints #tableSchema, #tableName, 'FOREIGN KEY';
FETCH NEXT FROM table_cursor INTO #tableSchema, #tableName
END
-- Drop Primary Keys
FETCH FIRST FROM table_cursor INTO #tableSchema, #tableName
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC #DropConstraints #tableSchema, #tableName, 'PRIMARY KEY';
FETCH NEXT FROM table_cursor INTO #tableSchema, #tableName
END
-- Drop Tables
FETCH FIRST FROM table_cursor INTO #tableSchema, #tableName
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC ('DROP TABLE ' + #tableSchema + '.' + #tableName);
FETCH NEXT FROM table_cursor INTO #tableSchema, #tableName
END
-- Cleanup
CLOSE table_cursor
DEALLOCATE table_cursor
COMMIT TRANSACTION
GO
You can use the INFORMATION_SCHEMA set of views to generate SQL Scripts to drop all the objects.
You don't have to drop items like indices, triggers, constraints, because they get dropped when you drop the table that they are attached to.
Brute Force Alert
Now tables themselves are tricky because of relationships.
If you separate each drop statement with a GO, you can keep running the script until you have no errors, and then you will have a clean slate.
UnbruteForcing based on feedback
Now, if delete all the foreign keys first, then you can drop all tables in a single go.