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

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.

Related

SQL Query all Databases

I need the run the following query on many databases, I have over 100+ databases, but I don't want to pull up each database and run the query one at a time.
The User table is only listed in Database#_Account.
If the query is ran it errors out because Database#_Admin does not have User Table.
(EXAMPLE Database List)
Database:
---------------------
MASTER
Model
msdb
tempdb
Database1_Account
Database1_Admin
Database2_Account
Database2_Admin
Database3_Account
Database3_Admin
Query:
EXEC sp_MsForEachDb #command1 = SELECT "?" as DatabaseName, *
FROM ?.User
WHERE Name = "John" AND "?" LIKE "%_Account"
ms_foreachDb is still an undocumented function and it subject to change anytime. I would use a cursor for something like this.
Here is a working template to get you started:
DECLARE #tsql nvarchar(max)
DECLARE #dbname varchar(500)
DECLARE MyCur CURSOR STATIC FORWARD_ONLY FOR
SELECT [name]
FROM sys.databases
WHERE [name] NOT IN ('tempdb')
OPEN MyCur
WHILE (1=1)
BEGIN
FETCH NEXT FROM MyCur INTO #dbname
IF ##FETCH_STATUS <> 0
BREAK
SET #tsql = 'use ' + #dbname + ' SELECT * FROM sys.tables'
EXEC sp_executesql #tsql
END
CLOSE MyCur;
DEALLOCATE MyCur;
You need to pass the command as an nvarchar literal, not as a query.
You need to use the correct nomenclature. You've left out the schema name. It's Database.Schema.Table, not Database.Table. I'm assuming all tables use the default dbo schema.
Write the query to test if the table exists before executing. Easiest way to do that is with IF OBJECT_ID(N'TableName') IS NOT NULL.
Avoid double quotes. They're normally field identifiers like square brackets are, so they're potentially ambiguous when used for varchar literals.
Try:
EXEC sp_MsForEachDb #command1 = N'IF OBJECT_ID(N''?.dbo.User'') IS NOT NULL SELECT ''?'' as DatabaseName, * FROM ?.dbo.User WHERE Name = ''John'' AND ''?'' LIKE ''%_Account'''
Here's the query I use to do a while loop to iterate through Databases.
Just put your code where it says PUT CODE HERE.
SET NOCOUNT ON
DECLARE #Database TABLE (DbName SYSNAME)
DECLARE #DbName AS SYSNAME
SET #DbName = ''
INSERT INTO #Database (DbName)
SELECT NAME
FROM master.dbo.sysdatabases
WHERE NAME <> 'tempdb'
ORDER BY NAME ASC
WHILE #DbName IS NOT NULL
BEGIN
SET #DbName = (
SELECT MIN(DbName)
FROM #Database
WHERE DbName > #DbName
)
/*
PUT CODE HERE
EXAMPLE PRINT Database Name
*/
PRINT #DbName
END
To create a list of users that match certain conditions you can modify this script.

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

Use “insert into” only with databases that has a certain table ( SQL Server 2008 R2 )

I need to do a "log" with all the information of a certain table, of all databases, inside a new table that I will create (With the same structure).
But not all databases has this table.
I could make a query to find all databases that has this table I want:
SELECT name
FROM sys.databases
WHERE CASE
WHEN state_desc = 'ONLINE'
THEN OBJECT_ID(QUOTENAME(name) + '.[dbo].[tblLogdiscador]', 'U')
END IS NOT NULL
It will only list the databases with this table I want to log. But now I need to do a loop, to pass by all databases, inserting the information of the "tbllogdiscador" into the table I created. I was thinking in SP_MSFOREACHDB but I see a lot of people saying to not use it.
How can I loop trough all databases that has the table, and if it has, insert into the new log table??
The code below is not helping me:
exec sp_msforeachdb 'if ((select count(*)
from [?].sys.tables Where name in(''tbllogdiscador''))=1)
begin
insert into [The new tbl log]
select * from ?.dbo.tbllog
end
I'm trying to use a cursor, but i'm having problems.
Any Ideas how to do this with WHILE?
To do what you are thinking, you need some kind of process flow logic (A cursor seems to be the most fitting choice), and dynamic sql.
So the high level is we need to get all of the DB names, put them into the cursor, and then use the cursor to execute the dynamic sql statement where you test to see of the table exists, and pull the records if so.
Ok so here is an example cursor that loops through the DBs on a server looking for a particular table name, and if it exists, does something (you'll have to do the sql for #Sql2):
declare #DBName varchar(256)
declare #SQL1 nvarchar(max)
declare #Sql2 nvarchar(max)
DECLARE db_cursor CURSOR FOR
SELECT name
FROM sys.databases
WHERE state_desc = 'ONLINE'
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #DBName
WHILE ##FETCH_STATUS = 0
Begin
set #SQL1 = 'Select Name from ' + #DBName + '.sys.objects where name = ''tblLogdiscador'' '
set #SQL2 = --Your select and insert statement selecting from #DBName + 'dbo.tbllogdiscador'
if exists(exec sp_executesql #Sql1)
begin
exec sp_executesql #sql2
end
FETCH NEXT FROM db_cursor INTO #DBName
end
close db_cursor
deallocate db_cursor

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;';

Update tables with same name different schemas

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'