SQL query on certain database names - sql

I currently have many databases on a server. I want to run a query on only databases that end in "AccountsLive".
Not all of them end with this, so I kind of want to do a wildcard %AccountsLive query and not using a WHERE NOT name IN('master', 'tempdb', 'model', 'msdb')
Is this possible?
Below is the code I currently have:
DECLARE #Sql NVARCHAR(MAX) = NULL;
SELECT #Sql = COALESCE(#Sql + ' UNION ALL ' + CHAR(13) + CHAR(10), '' ) + 'SELECT * FROM ' + QUOTENAME([name]) + '.SL_TRANSACTIONS'
FROM sys.databases
WHERE not [name] in ('master', 'tempdb', 'model', 'msdb');
EXECUTE ( #Sql );

You can put list of table names in a table variable and query them accordingly. I have also added schema as dbo, to make the name as three part name, assuming the table in the dbo schema.
DECLARE #table table(dbname sysname)
INSERT INTO #table(dbname)
SELECT NAME FROm sys.databases where name like '%AccountsLive'
DECLARE #Sql NVARCHAR(MAX) = NULL;
SELECT #Sql = COALESCE(#Sql + ' UNION ALL ' + CHAR(13) + CHAR(10), '' ) + 'SELECT * FROM ' + QUOTENAME(dbname) + '.dbo.SL_TRANSACTIONS'
FROM #table
EXEC( #Sql );

Related

'Msg 137, Level 16, State 1, Line 17 Must declare the scalar variable "#tempFinalTable"' error but #tempFinalTable is declared

(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)

Select all databases that have a certain table and a certain column

I need to create a query that is executed on all databases of my SQL server instance. An additional constraint is, that the query should only be executed on databases that contain a special table with a special column. Background is that in some databases the special table does (not) have the special column.
Based on this solution, what I have until now is a query that executes only on databases that contain a certain table.
SELECT *
FROM sys.databases
WHERE DATABASEPROPERTY(name, 'IsSingleUser') = 0
AND HAS_DBACCESS(name) = 1
AND state_desc = 'ONLINE'
AND CASE WHEN state_desc = 'ONLINE'
THEN OBJECT_ID(QUOTENAME(name) + '.[dbo].[CERTAIN_TABLE]', 'U')
END IS NOT NULL
However, what is still missing is a constraint that the query should only select databases where the table CERTAIN_TABLE has a specific column. How can this be achieved?
When i want to loop through all databases, i do a loop like the following. Its easy to follow:
DECLARE #dbs TABLE ( dbName NVARCHAR(100) )
DECLARE #results TABLE ( resultName NVARCHAR(100) )
INSERT INTO #dbs
SELECT name FROM sys.databases
DECLARE #current NVARCHAR(100)
WHILE (SELECT COUNT(*) FROM #dbs) > 0
BEGIN
SET #current = (SELECT TOP 1 dbName FROM #dbs)
INSERT INTO #results
EXEC
(
'IF EXISTS(SELECT 1 FROM "' + #current + '".INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = ''Target_Table_Name'' AND COLUMN_NAME = ''Target_Column_Name'')
BEGIN
--table and column exists, execute query here
SELECT ''' + #current + '''
END'
)
DELETE FROM #dbs
WHERE dbName = #current
END
SELECT * FROM #results
You are going to need either some looping or dynamic sql for this. I really dislike loops so here is how you could do this with dynamic sql.
declare #TableName sysname = 'CERTAIN_TABLE'
, #ColumnName sysname = 'CERTAIN_COLUMN'
declare #SQL nvarchar(max) = ''
select #SQL = #SQL + 'select DatabaseName = ''' + db.name + ''' from ' + QUOTENAME(db.name) + '.sys.tables t join ' + QUOTENAME(db.name) + '.sys.columns c on c.object_id = t.object_id where t.name = ''' + QUOTENAME(#TableName) + ''' and c.name = ''' + QUOTENAME(#ColumnName) + '''' + char(10) + 'UNION ALL '
from sys.databases db
where db.state_desc = 'ONLINE'
order by db.name
select #SQL = substring(#SQL, 0, len(#SQL) - 9)
select #SQL
--uncomment the line below when you are comfortable the query generated is correct
--exec sp_executesql #SQL

Query Across different database - Same table SQL Server 2012

I Have a common table "User Activity" in about 200 different databases on different servers, is it possible to select rows from all databases for that table in one statement?
I have a list of those databases and servers they are on ina main database/table, can obtain by
Select servername, dbname from DBases from CustomersList
Yes but you need to explicitly mention them all:
SELECT COl1,Col2,Col3 FROM Database1.schema.Table1
UNION ALL
SELECT COl1,Col2,Col3 FROM Database2.schema.Table1
UNION ALL
SELECT COl1,Col2,Col3 FROM Database3.schema.Table1
UNION ALL
.......
...
SELECT COl1,Col2,Col3 FROM Database200.schema.Table1
This is the kind of thing I would just build in Excel and paste into SSMS.
Then you might want to reconsider whether it's a good design to have this in 200 databases.
I am getting this error:
Incorrect syntax near 'ALL'
While I try to run your code.
I have address table in two databases so I modified your code as:
DECLARE #tableName nvarchar(256) = 'dbo.Address'
DECLARE #sql nvarchar(max) = ''
SELECT #sql = #sql + 'SELECT * FROM [' + dbs.name + ']..[' + #tableName + '] '
+ CASE WHEN #sql <> '' THEN 'UNION ALL ' ELSE '' END
FROM sys.sysdatabases dbs where dbs.dbid in (7,8)
and dbs.name NOT IN ('master', 'tempdb', 'msdb', 'model','SSISall')
EXEC(#sql)
I suggest you to use this syntax:
DECLARE #tableName nvarchar(256) = 'Table1'
DECLARE #sql nvarchar(max) = ''
SELECT #sql = #sql + CASE WHEN #sql <> '' THEN 'UNION ALL ' ELSE '' END
+ 'SELECT * FROM [' + dbs.name + ']..[' + #tableName + '] '
FROM sys.sysdatabases dbs
WHERE dbs.name NOT IN ('master', 'tempdb', 'msdb', 'model')
EXEC(#sql)
You can easily optimize it to use in a stored procedure.

query every single database

I would like to search every database in my DB search (they all have the same table name) with the following:
SELECT DISTINCT NAME FROM TABLE WHERE NAME = 'blah'
I have tried this:
SET NOCOUNT ON;
IF OBJECT_ID (N'tempdb.dbo.#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp
(
[COUNT] INT
, DB VARCHAR(50)
)
DECLARE #TableName NVARCHAR(50)
SELECT #TableName = '[dbo].[TABLE]'
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = STUFF((
SELECT CHAR(13) + 'SELECT ''' + name + ''', COUNT(1) FROM [' + name + '].' + #TableName
FROM sys.databases
WHERE OBJECT_ID(name + '.' + #TableName) IS NOT NULL
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
INSERT INTO #temp (DB, [COUNT])
EXEC sys.sp_executesql #SQL
SELECT *
FROM #temp t
The easiest way is to use (the undocumented) sp_msforeachdb. It's usage is:
exec sp_msforeachdb #command1 = N'insert into #tmp select "?", * from [?].dbo.table';
Of note is the ?, which is a placeholder for the database name. Within the #command1 string, double-quotes are used in place of single-quotes.
This procedure will also enumerate the system databases, and you can fairly easily sidestep that by appending if db_id("?") > 4 to skip them.

Quick way to backup SQL SP and Functions?

I have a long list of SPs (stored procedure) and Functions in my SQL server db. I could save them one by one by right clicking and script XXX to Alter To. Is there any way in TSQL to query all SPs and functions save them to xxx.sql files?
For example, for sp_mySP1, I would like to save it to sp_mySP1.sql which is a text file. The database is too big and I would like save only SPs and functions as a backup of source codes.
In management studio; find the database, right-click, tasks, generate scripts;
next-next-next until you "Choose Object Types". Select "Stored procedures" and "User-defined functions", next, Select All; choose an output; go!
1) Right-click on your Database name in the Object Explorer
2) Select "Tasks > Generate Scripts..." from the Context menu
3) Select your Database in the list and click Next
4) Click Next on the Chose Script Options
5) In Object Types, check Stored Procedures and User-defined functions, click Next
6) Click Select All on the Stored Procedures selection screen, click Next
7) Click Select All on the Functions selection screen, click Next
8) Select 'Script to New Query Window' and click Finish
Here's a proc that will export SOME types of data.
if exists ( select * from sysobjects where name = 'ExportData_P' )
drop proc ExportData_P
go
CREATE PROC dbo.ExportData_P (
#tableName varchar(500),
#where varchar(5000) = '(1=1)'
)
AS
BEGIN
SET NOCOUNT ON
DECLARE #sql varchar(8000)
DECLARE #fieldList varchar(8000)
DECLARE #valueList varchar(8000)
SELECT #fieldList = '', #valueList = ''
DECLARE #cols TABLE ( column_name nvarchar(250), data_type varchar(250) )
DECLARE #c nvarchar(250), #data_type varchar(250)
INSERT INTO #cols
select column_name, data_type
from information_Schema.columns
where table_name = #tableName
WHILE EXISTS ( SELECT TOP 1 * FROM #cols )
BEGIN
SELECT TOP 1 #c = column_name, #data_type = data_type FROM #cols
SELECT
#fieldList = #fieldList + #c + ', ',
#valueList = #valueList + CHAR(13) + 'case when ' + #c + ' is null then ''NULL'' else '''''''' + ' +
case when #data_type in ('text','ntext','char', 'nvarchar', 'varchar' ) then
' REPLACE ( REPLACE ( REPLACE ( '
else ''
end +
'IsNull ( convert(varchar' +
( -- change this section to pass the length of varchar to convert
case when #data_type in ( 'uniqueidentifier' ) then '(50)'
when #data_type in ( 'text', 'ntext' ) then '(8000)'
else '' end
) +
', ' +
#c +
'), '''' )' + -- end is null
case when #data_type in ('text','ntext','char', 'nvarchar', 'varchar' ) then
', CHAR(39), CHAR(39)+CHAR(39) ), CHAR(13), '''' + CHAR(13) + ''''), CHAR(9), '''' + CHAR(9) + '''') '
else ''
end +
' + '''''''' end + '', '' + '
DELETE FROM #cols WHERE column_name = #c
END
SELECT #fieldList = LEFT ( #fieldList, LEN(#fieldList)-1 ),
#valueList = LEFT ( #valueList, LEN(#valueList)-1 )
SELECT #sql = 'select ''insert into ' + #tableName + ' (' + #fieldList + ') ' +
' VALUES ( ''+ ' + left ( #valueList, len(#valueList)-5) + ''') '' from ' + #tableName +
' WHERE ' + #where
-- into [#mcoe_temp_export' + #tableName + ']
print #sql
EXEC ( #sql )
--EXEC ( 'select * from [#mcoe_temp_export' + #tableName + ']' )
SET NOCOUNT OFF
END
go
Use like:
exec ExportData_P 'tablename'
you could query syscomments to get your sql object creation text, but I don't know how to save them all in separate files using just TSQL.
select * from syscomments