I'm just trying to create tables in user databases apart from system databases.
here is the script
Declare #V table (ID INT,name varchar(100))
DECLARE
#DatabaseName VARCHAR(50),
#SQL NVARCHAR(MAX)
INSERT INTO #V(Id,name)
select ROW_NUMBER()OVER(ORDER BY NAME),
name
from sys.databases
where database_id >= 5
DECLARE #LoopCounter INT , #MaxId INT,
#Name NVARCHAR(100)
SELECT #LoopCounter = min(id) ,
#MaxId = max(Id)
FROM #V
WHILE(#LoopCounter IS NOT NULL
AND #LoopCounter <= #MaxId)
BEGIN
SELECT #Name = Name
FROM #V WHERE Id = #LoopCounter
set #Name = #DatabaseName
SET #SQL = N'USE ' + QUOTENAME(#DatabaseName)
+'CREATE TABLE T(ID INT)';
SET #LoopCounter = #LoopCounter + 1
-- PRINT(#DatabaseName);
--PRINT(#SQL);
EXECUTE(#SQL)
END
why is it not creating table dynamically?
how to get only user databases in below script
instead of giving manually
DECLARE #Sql AS VARCHAR(4000)
SET #Sql = 'IF ''?'' NOT IN (''master'',''tempdb'',''model'',''msdb'',''ReportServer'',''ReportServerTempDB'')
EXECUTE (''
USE [?] CREATE TABLE T (ID INT)'')'
EXEC sp_MSforeachdb
#command1 = #Sql
The problems with your script are here:
WHILE(#LoopCounter IS NOT NULL
AND #LoopCounter <= #MaxId)
BEGIN
SELECT #Name = Name
FROM #V WHERE Id = #LoopCounter
--set #Name = #DatabaseName -- this will assign value from #DatabaseName into #Name, but you should do the vice versa:
set #DatabaseName = #Name
SET #SQL = N'USE ' + QUOTENAME(#DatabaseName)
+' CREATE TABLE T(ID INT)'; -- I would also add space here, it might work with [XXX]create table
SET #LoopCounter = #LoopCounter + 1
-- PRINT(#DatabaseName);
--PRINT(#SQL);
EXECUTE(#SQL)
END
Because #DatabaseName was null, the result of your #SQL was null, and executing null is most likely just ok.
Your draft of the version with the sp_MSforeachdb procedure was also fine; you asked for a version without writing the names of the system databases. Unfortunately this has still not been implemented - there is no reliable flag or property on a database that would clearly identify it as a user database. Microsoft themselves apply the (inverted) criteria I am using below, when they list the contents of the "System Databases" folder in SSMS... see also here: https://stackoverflow.com/a/28590305/1132334
SELECT
[name]
FROM sys.databases
WHERE CAST(CASE WHEN [name] IN ('master','model','msdb','tempdb') THEN 1 ELSE is_distributor END AS bit)=0
Here is a tested script:
DECLARE #sql varchar(max)
SET #sql='IF ''?'' IN (SELECT [name] FROM sys.databases WHERE CAST(CASE WHEN [name] IN (''master'',''model'',''msdb'',''tempdb'') THEN 1 ELSE is_distributor END AS bit)=0)
EXECUTE (''USE [?] CREATE TABLE T (ID int)'')'
EXEC sp_MSforeachdb #command1 = #Sql
Related
I am trying to run a Stored Procedure that Inserts into a Table.
I keep getting the Incorrect syntax near 'tbl_1_2'.
It doesn't Insert the data.I am using MSSQL2012
Alter PROCEDURE [dbo].[TT] AS
BEGIN
declare #tbl varchar(100);
set #tbl='tbl_1_2';
declare #sql varchar(100);
DECLARE #ptablename VARCHAR(max) = (#tbl)
set #ptablename=#tbl
SET #sql = 'INSERT INTO ' + #ptablename ;
EXEC (#sql)
select *
from (
values('1','2')
) t1 (c1, c2)
End
See this sample and compare with your code to understand your error.
Create Table Test (ID int, Name sysname)
Go
Declare #TableName sysname = 'Test'
DECLARE #ID int = 1
DECLARE #Name sysname = 'Meysam'
Declare #SQL nVarchar(4000) = 'INSERT #TableName (ID, Name) Values (#ID, N''#Name'')'
Set #SQL = REPLACE(#SQL, '#TableName', #TableName)
Set #SQL = REPLACE(#SQL, '#ID', #ID)
Set #SQL = REPLACE(#SQL, '#Name', #Name)
EXEC (#SQL)
SELECT * FROM Test
I have 50 tables and I want to get list of all column names containing specific value in the column.
Something like: if 'Test' in column give me the column name. And I want to apply it for all 50 tables
Tables names are: abc1,abc2,abc3, … abcn.
There must be a better way to do this, but I did come across a query like this from a colleague a couple of years ago and I found the below (or a script similar to below that i may have tweaked before sending onto him) somewhere online (I imagine here on SO, but can't see to find where - I will update with link to original source if i can find it).
I would also just point out that this is a very heavy proc so I would take a backup of your db and restore it to a dev or test environment before executing it. Or even execute it against a test db that you might have in your localdb. The script searches all columns of all tables in a selected db for a string.
Personally I would probably export the data from each table to txt or csv and do a Find within them.
CREATE PROCEDURE FindMyData_String
#DataToFind NVARCHAR(4000),
#ExactMatch BIT = 0
AS
SET NOCOUNT ON
DECLARE #Temp TABLE(RowId INT IDENTITY(1,1), SchemaName sysname, TableName sysname, ColumnName SysName, DataType VARCHAR(100), DataFound BIT)
INSERT INTO #Temp(TableName,SchemaName, ColumnName, DataType)
SELECT C.Table_Name,C.TABLE_SCHEMA, C.Column_Name, C.Data_Type
FROM Information_Schema.Columns AS C
INNER Join Information_Schema.Tables AS T
ON C.Table_Name = T.Table_Name
AND C.TABLE_SCHEMA = T.TABLE_SCHEMA
WHERE Table_Type = 'Base Table'
And Data_Type In ('ntext','text','nvarchar','nchar','varchar','char')
DECLARE #i INT
DECLARE #MAX INT
DECLARE #TableName sysname
DECLARE #ColumnName sysname
DECLARE #SchemaName sysname
DECLARE #SQL NVARCHAR(4000)
DECLARE #PARAMETERS NVARCHAR(4000)
DECLARE #DataExists BIT
DECLARE #SQLTemplate NVARCHAR(4000)
SELECT #SQLTemplate = CASE WHEN #ExactMatch = 1
THEN 'If Exists(Select *
From ReplaceTableName
Where Convert(nVarChar(4000), [ReplaceColumnName])
= ''' + #DataToFind + '''
)
Set #DataExists = 1
Else
Set #DataExists = 0'
ELSE 'If Exists(Select *
From ReplaceTableName
Where Convert(nVarChar(4000), [ReplaceColumnName])
Like ''%' + #DataToFind + '%''
)
Set #DataExists = 1
Else
Set #DataExists = 0'
END,
#PARAMETERS = '#DataExists Bit OUTPUT',
#i = 1
SELECT #i = 1, #MAX = MAX(RowId)
FROM #Temp
WHILE #i <= #MAX
BEGIN
SELECT #SQL = REPLACE(REPLACE(#SQLTemplate, 'ReplaceTableName', QUOTENAME(SchemaName) + '.' + QUOTENAME(TableName)), 'ReplaceColumnName', ColumnName)
FROM #Temp
WHERE RowId = #i
PRINT #SQL
EXEC SP_EXECUTESQL #SQL, #PARAMETERS, #DataExists = #DataExists OUTPUT
IF #DataExists =1
UPDATE #Temp SET DataFound = 1 WHERE RowId = #i
SET #i = #i + 1
END
SELECT SchemaName,TableName, ColumnName
FROM #Temp
WHERE DataFound = 1
GO
What is the best way to get the names of all of the tables in all Databases on all Sql Servers? There are many databases in many Servers. So I wanna list Server names and database names with table names.
For example
Id ServerName databaseName Tablename
1 server1 Product Vegetables
2 server2 Product Milks
3 server1 Customer People
Probably I will use following query with openquery() but I did'nt do it.
SET NOCOUNT ON
DECLARE #AllTables table (CompleteTableName nvarchar(4000))
INSERT INTO #AllTables (CompleteTableName)
EXEC sp_msforeachdb 'select ##SERVERNAME+''.''+''?''+''.''+s.name+''.''+t.name from [?].sys.tables t inner join sys.schemas s on t.schema_id=s.schema_id'
SET NOCOUNT OFF
SELECT * FROM #AllTables ORDER BY 1
delete from [DatabaseName].[dbo].[hak_tables]
declare #counter int;
declare #openquery nvarchar(2000), #tsql nvarchar(2000), #servername nvarchar(2000)
create table #temp(
id int,
servername nvarchar(50)
)
insert into #temp(id,servername)
values (1,'ServerName'),
(2,'[ServerName -2]'),
(3,'[ServerName -3]')
create table #tablehavuzu(
ID int identity (1,1),
sunucuAdi nvarchar(1000),
databaseName nvarchar(1000),
name nvarchar(1000),
type nvarchar(1000),
create_date datetime,
modify_date datetime
)
declare #cmd3 nvarchar(max)
set #counter = 1
while #counter <= (select count(1) from #temp)
begin
create table #databasename(
name nvarchar(1000),
counter int
)
set #servername = (select servername from #temp where id=#counter)
declare #sorg nvarchar(max)
set #sorg='insert into #databasename
select name,ROW_NUMBER() over(order by name asc) from '+#servername+'.master.sys.databases '
exec (#sorg)
declare #counter1 int;
set #counter1 = 1
declare #databaseCount int
set #databaseCount = (select count(1) from #databasename)
while #counter1 <= #databaseCount
begin
declare #databaseName nvarchar(1000),#sql nvarchar(1000)
begin try
set #databaseName = (select name from #databasename where counter=#counter1)
set #sql ='select ##SERVERNAME sunucuAdi, '''''+#databaseName+''''' as databaseName, name, type, create_date, modify_date from '+#servername+'.'+#databaseName+'.sys.tables'
set #cmd3= 'select * from openquery('+#servername+','''+#sql+''')'
insert into #tablehavuzu
exec (#cmd3)
end try
begin catch
end catch
set #counter1 = #counter1 +1;
end
set #counter = #counter + 1;
drop table #databasename
end
insert into [M3].[dbo].[hak_tables]
select * from #tablehavuzu
drop table #temp
drop table #tablehavuzu
The below query will list all the table of all the databases in an instance - So you can execute it in all the instances to get those -
declare #sql nvarchar(max);
select #sql =
(select ' UNION ALL
SELECT ' + + quotename(name,'''') + ' as database_name,
s.name COLLATE DATABASE_DEFAULT
AS schema_name,
t.name COLLATE DATABASE_DEFAULT as table_name
FROM '+ quotename(name) + '.sys.tables t
JOIN '+ quotename(name) + '.sys.schemas s
on s.schema_id = t.schema_id'
from sys.databases
where state=0
order by [name] for xml path(''), type).value('.', 'nvarchar(max)');
set #sql = stuff(#sql, 1, 12, '') + ' order by database_name,
schema_name,
table_name';
execute (#sql);
In Sql Server
I have sample script
Declare #V table (name varchar(100))
INSERT INTO #V(name)
select name from sys.databases where database_id > 6
select NAME from #V
If I execute this Script I get the user databases list
In my instance I have below Databases :
DatabaseName
mohan
Ravi
How can I dynamically append the Database names to below script and execute the script in below Databases
Declare #V table (ID INT,name varchar(100))
INSERT INTO #V(Id,name)
select ROW_NUMBER()OVER(ORDER BY NAME),name from sys.databases where database_id > 6
DECLARE #LoopCounter INT , #MaxId INT,
#Name NVARCHAR(100)
SELECT #LoopCounter = min(id) , #MaxId = max(Id)
FROM #V
WHILE(#LoopCounter IS NOT NULL
AND #LoopCounter <= #MaxId)
BEGIN
SELECT #Name = Name
FROM #V WHERE Id = #LoopCounter
PRINT #Name
SET #LoopCounter = #LoopCounter + 1
END
DECLARE #DatabaseName VARCHAR(50) = #Name
, #SQL NVARCHAR(MAX);
SET #SQL = N'USE ' + QUOTENAME(#DatabaseName)
+'CREATE TABLE T(ID INT)';
--PRINT(#SQL);
EXECUTE(#SQL);
So in all user databases Table will be created . I have tried with sp_msforeachdb
script :
DECLARE #Sql AS VARCHAR(4000)
SET #Sql = 'IF ''?'' NOT IN (''master'',''tempdb'',''model'',''msdb'',''ReportServer'',''ReportServerTempDB'')
EXECUTE ('' USE [?] CREATE TABLE T (ID INT)'')'
EXEC sp_MSforeachdb #command1 = #Sql
But I'm looking for looping script .How to append those names to the Script
No need for a loop here. You can generate the entire statement in one pass. This query populates a var that contains multiple USE and CREATE TABLE statements:
DECLARE #Qry NVARCHAR(MAX) = '';
-- Build dynamic SQL statement here.
-- 1 Row returned per target database .
SELECT
#Qry +=
'
USE' + QUOTENAME(Name) + ';
CREATE TABLE T
(
ID INT
)
;
'
FROM
sys.Databases
WHERE
database_id > 6
;
-- Remove comments from last line when happy with query.
PRINT #Qry
--EXECUTE sp_ExecuteSQL #Qry
Returns
USE [X];
CREATE TABLE T
(
ID INT
)
;
USE [Y];
CREATE TABLE T
(
ID INT
)
;
...
I was wondering if someone could help me with creating a while loop to iterate through several databases to obtain data from one table from two columns. this is was I have done so far. nothing works because i do not know how to make the select statement work through each database with regards to the table that I am querying from each database (dbo.tbldoc)
DECLARE #Loop int
DECLARE #DBName varchar(300)
DECLARE #SQL varchar(max)
DECLARE #tableName VARCHAR(255)
SET #Loop = 1
SET #DBName = ''
WHILE #Loop = 1
BEGIN
SELECT [name] FROM sys.databases
WHERE [name] like 'z%' and create_date between '2010-10-17' and '2011-01-15'
ORDER BY [name]
SET #Loop = ##ROWCOUNT
IF #Loop = 0
BREAK
SET #SQL = ('USE ['+ #DBNAME +']')
IF EXISTS(SELECT [name] FROM sys.tables WHERE name != 'dbo.tbldoc' )
BEGIN
SELECT SUM(PGCOUNT), CREATED FROM **dbo.tbldoc**
END
ELSE
--BEGIN
PRINT 'ErrorLog'
END
I would consider sp_MSForEachDB which is a lot easier...
Edit:
EXEC sp_MSForEachDB 'USE [?]; IF DB_NAME() LIKE ''Z%%''
BEGIN
END
'
CREATE TABLE #T
(dbname sysname NOT NULL PRIMARY KEY,
SumPGCOUNT INT,
CREATED DATETIME)
DECLARE #Script NVARCHAR(MAX) = ''
SELECT #Script = #Script + '
USE ' + QUOTENAME(name) + '
IF EXISTS(SELECT * FROM sys.tables WHERE OBJECT_ID=OBJECT_ID(''dbo.tbldoc''))
INSERT INTO #T
SELECT db_name() AS dbname, SUM(PGCOUNT) AS SumPGCOUNT, CREATED
FROM dbo.tbldoc
GROUP BY CREATED;
'
FROM sys.databases
WHERE state=0 AND user_access=0 and has_dbaccess(name) = 1
AND [name] like 'z%' and create_date between '2010-10-17' and '2011-01-15'
ORDER BY [name]
IF (##ROWCOUNT > 0)
BEGIN
--PRINT #Script
EXEC (#Script)
SELECT * FROM #T
END
DROP TABLE #T
My code to search for data from more than one database would be:
use [master]
go
if object_id('tempdb.dbo.#database') is not null
drop TABLE #database
go
create TABLE #database(id INT identity primary key, name sysname)
go
set nocount on
insert into #database(name)
select name
from sys.databases
where name like '%tgsdb%' --CHANGE HERE THE FILTERING RULE FOR YOUR DATABASES!
and source_database_id is null
order by name
Select *
from #database
declare #id INT, #cnt INT, #sql NVARCHAR(max), #currentDb sysname;
select #id = 1, #cnt = max(id)
from #database
while #id <= #cnt
BEGIN
select #currentDb = name
from #database
where id = #id
set #sql = 'select Column1, Column2 from ' + #currentDb + '.dbo.Table1'
print #sql
exec (#sql);
print '--------------------------------------------------------------------------'
set #id = #id + 1;
END
go
DECLARE #Loop int
DECLARE #MaxLoop int
DECLARE #DBName varchar(300)
DECLARE #SQL varchar(max)
SET #Loop = 1
SET #DBName = ''
set nocount on
SET #MaxLoop = (select count([name]) FROM sys.databases where [name] like 'Z%')
WHILE #Loop <= #MaxLoop
BEGIN
SET #DBName = (select TableWithRowsNumbers.name from (select ROW_NUMBER() OVER (ORDER by [name]) as Row,[name] FROM sys.databases where [name] like 'Z%' ) TableWithRowsNumbers where Row = #Loop)
SET #SQL = 'USE [' + #DBName + ']'
exec (#SQL)
...
...
set #Loop = #Loop + 1
END
***Note: I didn't add the check if exists here.
I ended up writing one last week on the fly for some stuff I was doing.
Blog post here:
http://tsells.wordpress.com/2012/02/14/sql-server-database-iterator/
Here is the code.
SET NOCOUNT ON
GO
use master
go
Declare
#dbname nvarchar(500),
#variable1 int,
#variable2 int,
#variable3 int,
#totaldb int = 0,
#totaldbonserver int = 0,
#totaldbwithmatches int = 0
-- Get non system databases
Declare mycursor CURSOR for select name, database_id from SYS.databases where database_id > 4 order by name desc
open mycursor
fetch next from mycursor into #dbname, #variable1
while (##FETCH_STATUS <> -1)
BEGIN
DECLARE #ParmDefinition NVARCHAR(500)
Declare #mysql nvarchar(500) = 'select #variable2OUT = COUNT(*) from [' + #dbname + '].INFORMATION_SCHEMA.TABLES where Upper(TABLE_NAME) like ''MyTable''';
SET #ParmDefinition = N'#variable2OUT int OUTPUT'
set #totaldbonserver = #totaldbonserver + 1
Execute sp_executesql #mysql, #ParmDefinition, #variable2 OUTPUT
if #variable2 = 1
BEGIN
DECLARE #ParmDefinition2 NVARCHAR(500)
Declare #mysql2 nvarchar(500) = 'select #variable2OUT = COUNT(*) from [' + #dbname + '].dbo.MyTable';
SET #ParmDefinition2 = N'#variable2OUT int OUTPUT'
Execute sp_executesql #mysql2, #ParmDefinition2, #variable3 OUTPUT
set #totaldb = #totaldb + 1
if #variable3 > 1
BEGIN
Print #dbname + ' matched the criteria'
set #totaldbwithmatches = #totaldbwithmatches + 1
END
ELSE
Select 1
END
fetch next from mycursor into #dbname, #variable1
END
PRINT 'Total databases on server: '
Print #totaldbonserver
PRINT 'Total databases tested () : '
Print #totaldb
PRINT 'Total databases with matches: '
Print #totaldbwithmatches
CLOSE mycursor
DEALLOCATE mycursor
This doesn't use a loop. Hope this helps!
Note that "TABLE_OWNER" is that same as "SCHEMA Owner" and "TABLE_TYPE" will identify if the item is a table OR view.
--This will return all tables, table owners and table types for all database(s) that are NOT 'Offline'
--Offline database information will not appear
Declare #temp_table table(
DB_NAME varchar(max),
TABLE_OWNER varchar(max),
TABLE_NAME varchar(max),
TABLE_TYPE varchar(max),
REMARKS varchar(max)
)
INSERT INTO #temp_table (DB_NAME, TABLE_OWNER, TABLE_NAME, TABLE_TYPE,REMARKS)
EXECUTE master.sys.sp_MSforeachdb 'USE [?]; EXEC sp_tables'
SELECT DB_NAME, TABLE_OWNER, TABLE_NAME, TABLE_TYPE
FROM #temp_table
--Uncomment below if you are seaching for 1 database
--WHERE DB_NAME = '<Enter specific DB Name>'
--For all databases other than 'System Databases'
WHERE DB_NAME not in ('master','model','msdn','tempdb')
order by 1,2,3
You don't have to use a "USE DATABASE" statement. You can select from the particular database table by using a 3 part identifier as in:
select * from MyDatabase.dbo.MyTable