Drop all constraints from tables with a certain prefix - sql

I'm trying to delete certain tables from my database that have a certain prefix using SQL Server 2014, these tables have constraints of course, so I looked for the equivalent of SET foreign_key_checks = 0 in MySQL and so far i tried this :
Attempt
Running
EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
then drop all tables with this generated script :
SELECT 'drop table ' + table_name
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'myprefix%'
then
EXEC sp_msforeachtable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL'
Result
Some tables were deleted, and some threw an error
... is referenced by a FOREIGN KEY constraint.
which is weird because I thought that the stored procedure I ran disabled them.
Is there a way to delete these constraints all-together? Since I have the scripts to create them again, is there a way I can delete the constraints from sys.foreign_keys but only from the tables that have the prefix?
Edit - Context
I was working in isolation on an existing module that's part of our huge web app, now it's time to include the changes I made and sync them with the dev database, I was asked to generate the scripts to update it for all the tables, views, stored procedures.. etc that I created.
So, instead of doing scripts that add columns to existing tables, I though it'd be much easier to just drop the tables, and then re-create them, data is not important here, it's all dummy data I used while testing.

Since you mentioned already having the scripts required to regenerate the foreign keys, here's a way to generate and execute the drops. You might want to add some error handling.
declare #sql varchar(max);
declare c cursor local fast_forward for
select concat
(
'alter table ',
quotename(s.name),
'.',
quotename(t.name),
' drop constraint ',
quotename(fk.name)
)
from sys.foreign_keys fk
join sys.tables t on t.object_id = fk.parent_object_id
join sys.schemas s on t.schema_id = s.schema_id
where t.is_ms_shipped = 0
and t.name like 'myprefix%';
open c;
fetch next from c into #sql;
while (##fetch_status = 0)
begin
print #sql;
--exec(#sql); uncomment after checking output and run again (or just run output manually)
fetch next from c into #sql;
end

Related

Delete all tables in SQL Server database except few

I have around 50+ table in my database now what I want is drop all the tables in database except few.
now what I know is sys.tables is a table that list all tables so initially I ran a query like this
delete from sys.tables where name like '%DynamicSurgery' (or any other condition)
thinking that it might work. But as I expected it throws an error as
Ad hoc updates to system catalogs are not allowed.
Please tell me if there is a way to delete multiples in SQL Server?
You can use dynamic query to DROP the required tables:
DECLARE #ExecSQL AS NVARCHAR (MAX) = '';
SELECT #ExecSQL = #ExecSQL +
'DROP TABLE ' + QUOTENAME(S.name) + '.' + QUOTENAME(T.name) + '; '
FROM sys.tables T
JOIN sys.schemas S ON S.schema_id = T.schema_id
WHERE T.name LIKE '%DynamicSurgery'
--PRINT #ExecSQL
EXEC (#ExecSQL)
EXEC sys.sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL';
EXEC sp_MSforeachtable 'IF OBJECT_ID(''?'') NOT IN (
ISNULL(OBJECT_ID(''[dbo].[Table1]''),0),
ISNULL(OBJECT_ID(''[dbo].[Table2]''),0)
)
DELETE FROM ?';
EXEC sys.sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL';
select the table by clicking on it
press the delete button and hit enter.
Take note : if there is any dependencies(Foreign Key), the table will not be deleted

SQL Server -- updating the `sys.*` tables and not just reading them

In an attempt to the query
UPDATE sys.columns
SET user_type_id = 106
WHERE object_id in (select object_id from sys.objects where type = 'U') and user_type_id = 108
I'm getting the error:
Msg 259, Level 16, State 1, Line 1
Ad hoc updates to system catalogs are not allowed.
Is there a way to get around this? In this case, I'm looking to change the types of all decimal fields of all the tables in the database.
Can do this "externally"-- without direct tampering with sys.* tables (haven't yet pinned down how-to though), but I'm looking to know whether I can update the sys.* tables -- and if so, which ones, when/how?
// =========================
EDIT:
would i be able to get any "deeper" than alter table... if i had full privileges for db access?
not sure what kind of privileges i have now, but would look into it.
These tables are informational only. I want to make this clear: the sys.* and INFORMATION_SCHEMA.* views exist to provide schema information from the database engine in a useful format. They do not represent the actual schema of the database*, and modifying them is thus impossible. The only way to change your schema is to use DDL (Data Definition Language) statements, such as ALTER TABLE.
In your case, you can use a cursor to iterate through all columns with the wrong type, generate SQL statements to correct that, and execute them dynamically. Here's a skeleton of how that would look:
DECLARE column_cursor CURSOR FOR
SELECT schemas.name AS schema_name,
objects.name AS table_name,
columns.name AS column_name
FROM sys.columns
JOIN sys.objects
ON objects.object_id = columns.object_id
JOIN sys.schemas
ON schemas.schema_id = objects.schema_id
WHERE objects.type = 'U'
AND columns.user_type_id = 108
DECLARE #schema_name VARCHAR(255)
DECLARE #table_name VARCHAR(255)
DECLARE #column_name VARCHAR(255)
OPEN column_cursor
FETCH NEXT FROM column_cursor INTO #schema_name, #table_name, #column_name
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #sql VARCHAR(MAX)
-- TODO: modify to change to the actual type, scale and precision you want; also you may need to adjust for NOT NULL constraints, default constraints and foreign keys (all exercises for the reader)
SET #sql = 'ALTER TABLE ' + QUOTENAME(#schema_name) + '.' + QUOTENAME(#table_name) + ' CHANGE COLUMN ' + QUOTENAME(#column_name) + ' DECIMAL(12, 2)'
EXEC(#sql)
FETCH NEXT FROM column_cursor INTO #schema_name, #table_name, #column_name
END
CLOSE column_cursor
DEALLOCATE column_cursor
Because of the potential increase in complexity for dealing with constraints and keys, I'd recommend either updating the columns manually, building the ALTER TABLE statements manually, dumping your schema to script, updating that and recreating the tables and objects, or looking for a 3rd party tool that does this kind of thing (I don't know of any).
*For the sys.* views, at least, it's possible that they closely represent the underlying data structures, though I think there's still some abstraction. INFORMATION_SCHEMA is ANSI-defined, so it is unlikely to match the internal structures of any database system out there.

Drop all objects in SQL Server database that belong to different schemas?

Is there a way to drop all objects in a db, with the objects belonging to two different schemas?
I had been previously working with one schema, so I query all objects using:
Select * From sysobjects Where type=...
then dropped everything I using
Drop Table ...
Now that I have introduced another schema, every time I try to drop it says something about I don't have permission or the object does not exist. BUT, if I prefix the object with the [schema.object] it works. I don't know how to automate this, cause I don't know what objects, or which of the two schemas the object will belong to. Anyone know how to drop all objects inside a db, regardless of which schema it belongs to?
(The user used is owner of both schemas, the objects in the DB were created by said user, as well as the user who is removing the objects - which works if the prefix I used IE. Drop Table Schema1.blah)
Use sys.objects in combination with OBJECT_SCHEMA_NAME to build your DROP TABLE statements, review, then copy/paste to execute:
SELECT 'DROP TABLE ' +
QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + '.' +
QUOTENAME(name) + ';'
FROM sys.objects
WHERE type_desc = 'USER_TABLE';
Or use sys.tables to avoid need of the type_desc filter:
SELECT 'DROP TABLE ' +
QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + '.' +
QUOTENAME(name) + ';'
FROM sys.tables;
SQL Fiddle
Neither of the other questions seem to have tried to address the all objects part of the question.
I'm amazed you have to roll your own with this - I expected there to be a drop schema blah cascade. Surely every single person who sets up a dev server will have to do this and having to do some meta-programming before being able to do normal programming is seriously horrible. Anyway... rant over!
I started looking at some of these articles as a way to do it by clearing out a schema: There's an old article about doing this, however the tables mentioned on there are now marked as deprecated. I've also looked at the documentation for the new tables to help understand what is going on here.
There's another answer and a great dynamic sql resource it links to.
After looking at all this stuff for a while it just all seemed a bit too messy.
I think the better option is to go for
ALTER DATABASE 'blah' SET SINGLE_USER WITH ROLLBACK IMMEDIATE
drop database 'blah'
create database 'blah'
instead. The extra incantation at the top is basically to force drop the database as mentioned here
It feels a bit wrong but the amount of complexity involved in writing the drop script is a good reason to avoid it I think.
If there seem to be problems with dropping the database I might revisit some of the links and post another answer
try this with sql2012 or above,
this script may help to delete all objects by selected schema
Note: below script for dbo schema for all objects but you may change in very first line #MySchemaName
DECLARE #MySchemaName VARCHAR(50)='dbo', #sql VARCHAR(MAX)='';
DECLARE #SchemaName VARCHAR(255), #ObjectName VARCHAR(255), #ObjectType VARCHAR(255), #ObjectDesc VARCHAR(255), #Category INT;
DECLARE cur CURSOR FOR
SELECT (s.name)SchemaName, (o.name)ObjectName, (o.type)ObjectType,(o.type_desc)ObjectDesc,(so.category)Category
FROM sys.objects o
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
INNER JOIN sysobjects so ON so.name=o.name
WHERE s.name = #MySchemaName
AND so.category=0
AND o.type IN ('P','PC','U','V','FN','IF','TF','FS','FT','PK','TT')
OPEN cur
FETCH NEXT FROM cur INTO #SchemaName,#ObjectName,#ObjectType,#ObjectDesc,#Category
SET #sql='';
WHILE ##FETCH_STATUS = 0 BEGIN
IF #ObjectType IN('FN', 'IF', 'TF', 'FS', 'FT') SET #sql=#sql+'Drop Function '+#MySchemaName+'.'+#ObjectName+CHAR(13)
IF #ObjectType IN('V') SET #sql=#sql+'Drop View '+#MySchemaName+'.'+#ObjectName+CHAR(13)
IF #ObjectType IN('P') SET #sql=#sql+'Drop Procedure '+#MySchemaName+'.'+#ObjectName+CHAR(13)
IF #ObjectType IN('U') SET #sql=#sql+'Drop Table '+#MySchemaName+'.'+#ObjectName+CHAR(13)
--PRINT #ObjectName + ' | ' + #ObjectType
FETCH NEXT FROM cur INTO #SchemaName,#ObjectName,#ObjectType,#ObjectDesc,#Category
END
CLOSE cur;
DEALLOCATE cur;
SET #sql=#sql+CASE WHEN LEN(#sql)>0 THEN 'Drop Schema '+#MySchemaName+CHAR(13) ELSE '' END
PRINT #sql
EXECUTE (#sql)
I do not know wich version of Sql Server are you using, but assuming that is 2008 or later, maybe the following command will be very useful (check that you can drop ALL TABLES in one simple line):
sp_MSforeachtable "USE DATABASE_NAME DROP TABLE ?"
This script will execute DROP TABLE .... for all tables from database DATABASE_NAME. Is very simple and works perfectly. This command can be used for execute other sql instructions, for example:
sp_MSforeachtable "USE DATABASE_NAME SELECT * FROM ?"

Is there a simpler and faster way of dropping a table that has foreign key references to other tables?

I have a new table that has foreign key references to a number of existing tables. When I create the new table for the first time, I created the foreign keys in the following way:
ALTER TABLE [dbo].[NewTable] WITH CHECK ADD FOREIGN KEY([SectionDatabaseID])
REFERENCES [dbo].[Section] ([SectionDatabaseID])
ALTER TABLE [dbo].[NewTable] WITH CHECK ADD FOREIGN KEY([TermDatabaseID])
REFERENCES [dbo].[Term] ([TermDatabaseID])
The above way will generate names for the foreign key constraints using it's own automated naming convention.
However, I want to drop the new table because I need to do some major modifications by creating it from scratch.
Obviously, if I just execute a drop statement, the SQL Server database will complain stating that the new table has foreign key references to other tables.
I've heard of running the following script to figure out what foreign keys exist so that we can drop them:
use perls;
SELECT 'ALTER TABLE ' + TABLE_SCHEMA + '.[' + TABLE_NAME +
'] DROP CONSTRAINT [' + CONSTRAINT_NAME + ']'
FROM information_schema.table_constraints
WHERE CONSTRAINT_TYPE = 'FOREIGN KEY' and TABLE_NAME = 'NewTable'
The above will give results that basically show alter statements which I need to run.
I need something more automated. Why do I have to drop each foreign key constraint separately, and then only be able to drop the table?
I want to drop the table in a simpler way. It's got to be easier than what I need to do above.
Relational databases are designed to enforce database integrity. Your statements are potentially destroying constraints that were carefully added to protect the data quality. Automating the dropping of integrity constraints from a production database could be a disaster for a company. So when the SQL language was developed, making it easy to drop tables that are referenced by other tables was not high on the priority of important tasks. With a database engine for enterprise data, the product is designed more for DBAs than for casual users.
What is the reason for wanting to drop multiple tables that are being referenced in foreign keys? Can you be sure that you are not going to be destroying somebody else's queries?
Assuming that you are working on a non critical system, your approach of writing a script to write a drop script is about the best solution that I know of.
Yes you must drop the FKs first. I've ran into this before and have written just the script you need to automate the task. Replace DBName and TABLENAME below.
Warning to all: This script will drop a specific table (or group of tables) as well as all FK constraints! Use with caution, and always take a db backup before doing a major operation like this.
use DBName
/*
SCRIPT TO DROP TABLES WITH FK'S, INDEXES
https://mellodev.snipt.net/drop-tables-with-fk-contraints/
*/
set nocount on
declare #tables table (tablename varchar(255));
insert into #tables
select name from sys.tables where name in
('TABLENAME')
-- Iterate tables, drop FK constraints and tables
declare #tablename varchar(255);
declare cTable cursor for
select tablename from #tables
open cTable
fetch next from cTable into #tableName
while ##FETCH_STATUS=0
begin
-- Identify any FK constraints
declare #fkCount int;
SELECT #fkCount = COUNT(*)
FROM sys.foreign_keys
WHERE referenced_object_id = object_id(#tablename)
-- Drop any FK constraints from the table
if (#fkCount>0) begin
declare #dropFkSql nvarchar(max);set #dropFkSql='';
declare #fkName nvarchar(max);
declare cDropFk cursor for
SELECT 'ALTER TABLE [' + OBJECT_NAME(parent_object_id) + '] DROP CONSTRAINT [' + name + ']',name
FROM sys.foreign_keys
WHERE referenced_object_id = object_id(#tablename)
open cDropFk
fetch next from cDropFk into #dropfksql,#fkName
while ##FETCH_STATUS=0
begin
exec sp_executesql #dropFkSql;
select 'Dropped FK Constraint: ' + #fkName
fetch next from cDropFk into #dropfksql,#fkName
end
close cDropFk
deallocate cDropFk
end
-- Drop the table
declare #dropTableSql nvarchar(max);
set #dropTableSql='DROP TABLE [' + #tablename + ']';
exec sp_executesql #dropTableSql;
select 'Dropped table: ' + #tablename
fetch next from cTable into #tableName
end
close cTable
deallocate cTable
If you are using MSSQL then you can use this script that i wrote to purge the whole DB from data without dropping the tables themselves.
use [MyDataBase]
GO
EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL';
select tbl.* into dbo.DeleteQueries from (SELECT 'DELETE ' + name + ';' as query
FROM sys.tables
WHERE name <> 'DeleteQueries') as tbl
Declare #query nvarchar(100)
While (Select Count(*) From dbo.DeleteQueries Where query <> '') > 0
Begin
Select Top 1 #query = query From dbo.DeleteQueries Where query <> ''
exec(#query);
Update dbo.DeleteQueries Set query = '' Where query = #query
End
DROP TABLE dbo.DeleteQueries
EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
you can add tables that you don't want to purge in the where clause of the "select into" query.
Hope this helps

Adding a column to all user tables in t-sql

I need to add a delete flag column to all 40 user tables in a database. I could write a script to loop through sys.tables, but I thought I'd check and see if anyone has either a better solution, or pre-created sql for this scenario.
There is an undocumented but well known stored procedure sp_msforeachtable:
exec sp_msforeachtable 'alter table ? add flag bit not null default 0';
No, it's a manual loop.
Or you could build up a single SQL statement of course...
SELECT
'ALTER TABLE ' + T.name + ' ADD foo int NULL'
FROM
sys.tables AS T
WHERE
T.is_ms_shipped = 0
Or the undocumented
EXEC sys.sp_MSforeachtable 'ALTER TABLE ? ADD foo int NULL'