Copy SQL Server database for development but smaller - sql

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

Related

How to find, across multiple databases, a specific table (common to most/all) that is not empty

I am working in an environment where many users have the same (or almost identical) test database set up on a common MSSQL server. We are talking about well over 100 databases for testing purposes. And at the very least, 95+% of them will contain the table I am trying to target.
These test databases are only filled with junk data - I will not be impacting anyone by doing any kind of a search. I am looking at one table, specifically, and I need to determine if any test database has that table actually containing any data at all. It doesn’t matter what the data is, I just need to find a table actually containing any data, so I can determine why that data exists in the first place. (This DB is quite old - almost two decades, so sometimes no-one has a clear answer why something in it exists).
I have been trying to build an SQL statement that iterates through all the databases, and checks that particular table specifically to see if it has any content, to bring back a list of databases that have that table containing data.
So to be specific: I need to find all databases where a specific table has any content at all (COUNT(*) > 0). Right now totally stuck with not much of any clues as to how to proceed.
In both methods replace <tablename> with the table name
Using sp_foreachdb
You can use sp_foreachDb
CREATE TABLE ##TBLTEMP(dbname varchar(100), rowscount int)
DECLARE #command varchar(4000)
SELECT #command =
'if exists(select 1 from [?].INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME =''<TABLE NAME>'') insert into ##TBLTEMP(dbname,rowscount) select ''[?]'',count(*) from [?].dbo.<tablename>'
EXEC sp_MSforeachdb #command
SELECT * FROM ##TBLTEMP WHERE rowscount > 0
DROP TABLE ##TBLTEMP
Using CURSOR
CREATE TABLE ##TBLTEMP(dbname varchar(100), rowscount int)
DECLARE #dbname Varchar(100), #strQuery varchar(4000)
DECLARE csr CURSOR FOR SELECT [name] FROM sys.databases
FETCH NEXT FROM csr INTO #dbname
WHILE ##FETCH_STATUS = 0
BEGIN
SET #strQuery = 'if exists(select 1 from [' + #dbname +'].INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME =''<TABLE NAME>'') INSERT INTO ##TBLTEMP(dbname,rowscount) SELECT ''' + #dbname + '' ', COUNT(*) FROM [' + #dbname + '].[dbo].<table name>'
EXEC(#strQuery)
FETCH NEXT FROM csr INTO #dbname
END
CLOSE csr
DEALLOCATE csr
SELECT * FROM ##TBLTEMP where rowscount > 0
References
Sp MSforeachDB
Run same command on all SQL Server databases without cursors
DECLARE CURSOR (Transact-SQL)

SQL Query to delete data from tables defined in table

I'm trying to delete data from a number of tables in my SQL base.
In the database I have a table called company which contains the names of each table that I need to delete data from.
lets assume that I have 3 companies in my company table.
What I want to do is delete all records in some certain tables in each company.
So, in the company table I have the following 3 records:
1 2 3
There are also the following tables in the database which depicts each company's scanned documents.
dbo.1.documents
dbo.2.documents
dbo.3.documents
What I am trying to do is to create a SQL query that will run through the dbo.company table and clear the document tables based on the company names found there.
This is my code:
DECLARE #MyCursor CURSOR;
DECLARE #MyField varchar;
BEGIN
SET #MyCursor = CURSOR FOR
select top 1000 [Name] from dbo.Company
OPEN #MyCursor
FETCH NEXT FROM #MyCursor
INTO #MyField
WHILE ##FETCH_STATUS = 0
BEGIN
delete * from 'dbo.'+#MyField+'$documents'
FETCH NEXT FROM #MyCursor
INTO #MyField
END;
CLOSE #MyCursor ;
DEALLOCATE #MyCursor;
END;
I am not sure how the syntax should go but I imagine it is something like this.
Anybody care to chip in on how I can dynamically delete the data based on the records in the dbo.company.name?
Use dynamic sql.
Replace the delete-statement with code below (the declare can be done at the start):
DECLARE #sql NVARCHAR(1000)
SET #sql = N'delete from dbo.'+CONVERT(VARCHAR,#MyField)+'documents'
EXEC sp_executesql #sql
You can leverage dynamic sql a little differently and avoid all the hassle and overhead of creating a cursor for this. I am using the values in your table to generate a number of delete statements and then executing them. This is a lot less effort to code and eliminates that nasty cursor.
declare #SQL nvarchar(max) = ''
select #SQL = #SQL + 'delete dbo.[' + c.Name + '$documents];'
from dbo.Company
select #SQL --uncomment the line below when you are satisfied the dynamic sql is correct
--exec sp_executesql #sql

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

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'

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.