I have below query to create duplicate table :
select * into person1 from person
but know I need a query to create duplicate for each table in selected database.
To to this I tried like below:
Declare #Time nvarchar(10)=1
Declare #Comment nvarchar(max)
set #Comment ='select * into ?'+#Time + ' '+'from ?'
exec sp_msforeachtable #Comment
but it returns the error :
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '1'.
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '1'.
Is there a way to do this ?
Following our conversation in the comments I think you will have to use dynamic sql.
You can use something like this instead:
DECLARE #Sql nvarchar(max) = '';
SELECT #Sql = #Sql + 'SELECT * INTO '+ TABLE_NAME +'1 FROM '+ TABLE_NAME +';'
FROM INFORMATION_SCHEMA.TABLES
EXEC(#SQL)
update
The above code has some drawbacks.
First, it will fail if there is a table name that doesn't follow the identifier naming rules.
Second, it will also create tables from views.
Here's a better version, that fix these issues:
DECLARE #Sql nvarchar(max);
SET #Sql = STUFF(
(
SELECT ';SELECT * INTO '+ QUOTENAME(Table_Name + '1') +' FROM '+ QUOTENAME(Table_Name)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
FOR XML PATH('')
), 1, 1, '')
EXEC (#Sql)
Another improvement here is in the way the string gets aggregated - the first version is a RBAR approach, the second one isn't (at least, to the best of my knowledge).
Related
(Working with Microsoft SQL Server Management Studio)
I have a query that should, in theory, return a table containing all of the tables contained within the databases of the server to which I am connected.
However, whenever I run the query, I get the following error:
Msg 137, Level 16, State 1, Line 17
Must declare the scalar variable "#tempFinalTable".
The query itself
DECLARE #tempTableVariable TABLE (id INT NOT NULL IDENTITY(1,1), DB varchar(1000))
DECLARE #tempFinalTable TABLE (id INT NOT NULL IDENTITY(1,1), DB varchar(1000), TABLE_LOC varchar(1000))
DECLARE #DBIndex INT = 1
DECLARE #Query varchar(1000)
DECLARE #MyDB varchar(1000)
DECLARE #RowCount INT = (SELECT COUNT(*) FROM #tempTableVariable)
INSERT INTO #tempTableVariable
SELECT [name]
FROM MASTER.dbo.SYSDATABASES WITH (NOLOCK)
WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb')
WHILE #DBIndex < #RowCount
BEGIN
SET #MyDB = (SELECT DB FROM #tempTableVariable WHERE id = #DBIndex)
SET #Query = 'INSERT INTO'+ #tempFinalTable + ' (DB, TABLE_LOC)
SELECT TABLE_CATALOG, CONCAT(TABLE_CATALOG, ''.'', TABLE_SCHEMA, ''.'', TABLE_NAME)
FROM ' + #MyDB + '.INFORMATION_SCHEMA.TABLES
ORDER BY TABLE_CATALOG'
EXEC(#QUERY)
SET #DBIndex = #DBIndex + 1
END
SELECT *
FROM #tempFinalTable
Any guidance as to where I have made a mistake would be greatly appreciated.
Your primary issue is that you have a syntax error, because you are trying to use the value of the table variable as part of the dynamic SQL string, but only a scalar variable can be used like that.
Even if you put the table variable within the string properly, you would still run into scoping issues, because variables don't pass over to dynamic SQL.
A much better solution is to forgo the table variable, and instead build a UNION ALL query to select it straight from dynamic SQL.
Note also:
Object names are nvarchar(128) you can use the alias sysname
You need to quote names with QUOTENAME
Don't use dbo.sysdatabases and INFORMATION_SCHEMA, they're deprecated. Instead use sys.databases and sys.tables
DECLARE #sql nvarchar(max) = (
SELECT STRING_AGG(CAST('
SELECT
DB = ' + QUOTENAME(d.name, '''') + ',
TABLE_LOC = ' + QUOTENAME(d.name, '''') + ' + ''.'' + s.name + ''.'' + t.name
FROM ' + QUOTENAME(d.name) + '.sys.tables t
JOIN ' + QUOTENAME(d.name) + '.sys.schemas s ON s.schema_id = t.schema_id
'
AS nvarchar(max)), 'UNION ALL')
FROM sys.databases d
WHERE d.database_id > 4 -- not system DB
);
PRINT #sql; --for testing
EXEC sp_executesql #sql;
I can't say whether you need QUOTENAME within the dynamic query, because I don't know what result you want, or what you intend to do with the result. If need be, you can do
TABLE_LOC = QUOTENAME(' + QUOTENAME(d.name, '''') + ') + ''.'' + QUOTENAME(s.name) + ''.'' + QUOTENAME(t.name)
I thought this would be pretty straightforward, but I have about 80 databases in the server I am looking at, each database has 5-500 tables.
I am wondering how i can search for a TABLE NAME across everything. I tried a basic
SELECT
*
FROM sys.tables
but I only get 6 results.
This is a bit of a hack, but I think it should work:
sp_msforeachdb 'select ''?'' from ?.information_schema.tables where table_name=''YourTableName''';
It will output the names of the DBs that contain a table with the given name.
Here's a version using print that is a little better IMHO:
sp_msforeachdb '
if exists(select * from ?.information_schema.tables where table_name=''YourTableName'')
print ''?'' ';
The above queries are using ms_foreachdb, a stored procedure that runs a given query on all databases present on the current server.
This version uses FOR XML PATH('') instead of string concatenation, eliminates the default system databases, handles databases with non-standard names and supports a search pattern.
DECLARE #pattern NVARCHAR(128) = '%yourpattern%';
DECLARE #sql NVARCHAR(max) = STUFF((
SELECT 'union all select DatabaseName = name from ' + QUOTENAME(d.name) + '.sys.tables where name like ''' + #pattern + ''' '
FROM sys.databases d
WHERE d.database_id > 4
FOR XML path('')
), 1, 10, '');
EXEC sp_executesql #sql;
You might need to write:
select DatabaseName = name collate Latin1_General_CI_AS
I know I did.
Just because I really dislike loops I wanted to post an alternative to answers already posted that are using cursors.
This leverages dynamic sql and the sys.databases table.
declare #SQL nvarchar(max) = ''
select #SQL = #SQL + 'select DatabaseName = name from [' + name + '].sys.tables where name = ''YourTableName'' union all '
from sys.databases
set #SQL = stuff(#SQL, len(#SQL) - 9, 11, '') --removes the last UNION ALL
exec sp_executesql #SQL
Here's a bit of a simpler option using dynamic sql. This will get you the name of all tables in every database in your environment:
declare #table table (idx int identity, name varchar(max))
insert #table
select name from master.sys.databases
declare #dbname varchar(max)
declare #iterator int=1
while #iterator<=(select max(idx) from #table) begin
select #dbname=name from #table where idx=#iterator
exec('use ['+#dbname+'] select name from sys.tables')
set #iterator=#iterator+1
end
select * from #table
Dim sql As String = ("Select * from " & ComboboxDatabaseName.Text & ".sys.tables")
use this key
Why does this fail with the following error message:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 'reporting_rawdata_v2'.
the name of the table is "dbo.reporting_rawdata_v2" but either with/without "dbo" it still fails...
Use reporting2
Go
Declare #Backupdate varchar(25), #sql NVARCHAR(max)
Set #Backupdate = REPLACE(REPLACE(CAST(CONVERT(VARCHAR(20), SYSDATETIME(), 100) as varchar),' ','_'),':', '')
Select #Backupdate
SET #sql = 'Select * Into reporting_rawdata_BACKUP_' + #Backupdate + 'From reporting_rawdata_v2';
EXEC (#sql);
No space between dynamically named table and From
SET #sql = 'Select * Into reporting_rawdata_BACKUP_' + #Backupdate + ' From reporting_rawdata_v2';
EXEC (#sql);
I understand that you cannot include variables in OPENQUERY so the work around is dynamic SQL and I did the following:
DECLARE #etd AS DATETIME = '2014-06-28'
DECLARE #source AS VARCHAR(46)
DECLARE #dbName AS VARCHAR(30)
DECLARE #query AS VARCHAR(MAX)
DECLARE #openQuery AS VARCHAR(MAX)
SELECT TOP(1) #source = [Source], #dbName = DbName
FROM dbo.SomeTable
WHERE SystemCode = 'SomeSystem'
SET #query = 'SELECT *
FROM [' + #dbName + '].dbo.Table1 t1
LEFT JOIN [' + #dbName + '].dbo.Table2 t2 ON t1.bookno = t2.tranno
WHERE (YEAR(t1.etddate) = ' + CAST(YEAR(#etd) AS VARCHAR(4)) +
' AND MONTH(t1.etddate) = ' + CAST(MONTH(#etd) AS VARCHAR(2)) +
' AND DAY(t1.etddate) = ' + CAST(DAY(#etd) AS VARCHAR(2)) +')'
SET #openQuery = 'SELECT * FROM OPENQUERY([' + #source + '],''' + #query + ''')'
EXECUTE (#openQuery)
When I use SELECT #openQuery I don't see anything wrong with the query string, but once I execute it, I received the following error:
OLE DB provider "SQLNCLI11" for linked server "xxx.xxx.xxx.xxx,1433" returned message "Deferred prepare could not be completed.".
Msg 8180, Level 16, State 1, Line 1
Statement(s) could not be prepared.
Msg 208, Level 16, State 1, Line 1
Invalid object name 'xxxx.dbo.t1'. (where 'xxxx' is the table name variable)
I've been searching for answers but I cannot find any, I really need your help guys.
You might temporarily change the EXECUTE to PRINT (PRINT #openQuery), see what SQL is actually being generated, then attempt to run the generated sql directly in SSMS. It might be obvious when you see the generated sql, but if not, you might get a more descriptive error message.
I have created following stored procedure in SQL Server,
create procedure sp_test
#columns nvarchar(max),
#tablename nvarchar(max),
#whereClause nvarchar(max)
as
DECLARE #sql AS NVARCHAR(MAX)
SET #sql = 'SELECT ' + #columns + ' FROM ' + #tablename + #whereClause;
EXEC sp_executesql #sql
I am trying to call it like this
exec sp_test 'title,name','person','where name = ''john'''
And I'm getting an error like this,
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '='.
You have an extra single quote, why not use double quote, like:
exec sp_test 'title,name','person'," where name = 'john'"
Add an extra space also here:
SET #sql = 'SELECT ' + #columns + ' FROM ' + #tablename+ ' ' + #whereClause;
Hint: It's because
SELECT title,name FROM personwhere name = 'john'
is not a valid SQL.
The reason should be obvious now and is left as an exercise to the reader...