Search a table name across multiple databases SQL SERVER 2019 - sql

I have a table, and the table name is AADatatimeBB in DatabaseB.
My SQL service Have multiple databases DatabaseA,DatabaseB,DatabaseC,DatabaseD
If I do not know the table: AADatatimeBB in which Database, how can I search it?
I can use the following query to search the table if I know the table in which Database.
Select the Database Name in the available Database list and run the query
SELECT * FROM INFORMATION_SCHEMA.TABLES
where table_name like '%DATASET%'

With the following query you can retrieve the names of all databases.
SELECT name, database_id, create_date
FROM sys.databases ;
GO
OR-----------------------------------
SELECT *
FROM sys.databases ;
GO
If you want the names of tables in a database, you can use the following query
USE master
GO
SELECT *
FROM information_schema.tables
GO
OR----------------------------
USE model
GO
SELECT *
FROM information_schema.tables
GO
OR-----------------------
USE ...
GO
SELECT *
FROM information_schema.tables
GO
The following code retrieves all databases and returns all tables of each database in a while loop.
Declare #tempTable Table
(
name varchar(100)
)
--Container to Insert records in the inner select for final output
Insert into #tempTable
SELECT name
FROM sys.databases
-- Keep track of #tempTable record processing
Declare #name varchar(100)
Declare #SQL VarChar(1000)
While((Select Count(*) From #tempTable)>0)
Begin
Set #name=(Select Top 1 name From #tempTable)
--get all db tables
SELECT #SQL = 'USE ' + QUOTENAME(#name) + ' SELECT * FROM information_schema.tables'
Exec (#SQL)
Delete #tempTable Where name=#name
End
If you want to use SQL LIKE Operator, follow the code below
SELECT #SQL = 'USE ' + QUOTENAME(#name) + ' SELECT * FROM information_schema.tables WHERE table_name LIKE ''%a%'''

Related

SQL Query against multiple databases

I'm trying to run a query against multiple databases on the same server.
I need to pull all the values from 2 tables in a database based on a criteria from a 3rd table in the database, if the database was created after a certain date.
I have a query to find when the database was created:
SELECT *
FROM sys.databases
WHERE STATE = 0 --ignores offline databases
AND database_id > 4 --does not include master, model, msdb, tempdb
AND create_date > CONVERT(datetime, '2021-01-01')
And the query that I need run on each database is generally as follows:
SELECT *
FROM Table1
INNER JOIN Table3 ON Table3.Column6=Table1.Column2
AND Table3.Column3='Value1'
AND Table3.Column4='Value2'
INNER JOIN Table2 ON Table3.Column6=Table2.Column2
I did find this question, which is essentially would I would like to do, but when I look at the INFORMATION_SCHEMA.TABLES the TABLE_CATALOG column does not have the table names I would like to query against. I thought I could try pulling the names from the sys.databases table like above, so I tried modifying it to:
DECLARE #cmd VARCHAR(max) = N''
SELECT #cmd += COALESCE(#cmd + ' UNION ALL ', '') + 'SELECT *
FROM [' + name + '].dbo.Table1
INNER JOIN [' + name + '].dbo.Table3 on Table3.Column6=Table1.Column2
AND Table3.Column3= ''Value1''
AND Table3.Column4=''Value2''
INNER JOIN [' + name + '].dbo.Table2 on Table3.Column6=Table2.Column2'
FROM sys.databases
WHERE STATE = 0
AND database_id>4
AND create_date>CONVERT(datetime,'2021-08-26')
SET #cmd = STUFF(#cmd, CHARINDEX('UNION ALL', #cmd), 10, '')
PRINT #cmd
EXEC(#cmd)
But when I run it with a date earlier than 2021-08-26 (which grabs more than 5 tables), I get a memory error. I need to run this at least to the beginning of April (preferably up to the beginning of the year) which will grab around 500 tables.
What is the recommended way to run a query against multiple databases in SQL?
My recommendation would be instead of trying to build one massive UNION ALL dynamic SQL statement, that you build a #temp table to hold the results of each output, and then it's much easier to send the same string to each database:
CREATE TABLE #hold(dbname sysname, Column1 {data type}, ...);
DECLARE #sql nvarchar(max), #exec nvarchar(1024);
SET #sql = N'SELECT DB_NAME(), *
FROM dbo.Table1
INNER JOIN dbo.Table3
ON Table3.Column6 = Table1.Column2
AND Table3.Column3 = ''Value1''
AND Table3.Column4 = ''Value2''
INNER JOIN dbo.Table2
ON Table3.Column6 = Table2.Column2;';
DECLARE #dbname sysname, #c cursor;
SET #c = CURSOR FORWARD_ONLY STATIC READ_ONLY FOR
SELECT name FROM sys.databases
WHERE state = 0 -- ignores offline databases
AND database_id > 4 -- does not include master, model, msdb, tempdb
AND create_date > CONVERT(datetime, '20210101');
OPEN #c;
FETCH NEXT FROM #c INTO #dbname;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #exec = QUOTENAME(#dbname) + N'.sys.sp_executesql';
INSERT #hold EXEC #exec #sql;
FETCH NEXT FROM #c INTO #dbname;
END;
SELECT * FROM #hold;
You might also consider investing in sp_ineachdb, a procedure I wrote to help simplify running the same command in the context of each database.
Execute a Command in the Context of Each Database in SQL Server using sp_ineachdb
Execute a Command in the Context of Each Database in SQL Server - Part 2

Find total number of data written in two same table from two different databases

I have been trying to write an easy query for my problem. I wrote something but it takes so long when I try to use it for 20 different database which is first I declare an integer than I keep adding the numbers that I summed each other it looks like this;
DECLARE #counter int
SET #counter = (SELECT COUNT(*) as TOTAL FROM database1.dbo.User);
SET #counter = #counter + (SELECT COUNT(*) as TOTAL FROM database2.dbo.User);
SET #counter = #counter + (SELECT COUNT(*) as TOTAL FROM database3.dbo.User);
PRINT #counter;
But I'm looking for an easier way because in my server there is more than 200 databases and I have to choose nearly 35 of them which there names starts same than they have numbers that defines them for example:
database1
database2
But other than that 35 of them are different names so I have to put something in my query that allows me to access the number of users in that database easily.
You could use the undocumented sp_MsForEachDb
The ? is replaced by the DB name.
Try something like:
CREATE TABLE #T (Total INT, DbName SYSNAME)
exec sp_MsForEachDb '
IF EXISTS (SELECT 1 FROM ?.sys.tables WHERE Name = ''Users'')
AND ''?'' LIKE ''Database%''
BEGIN
INSERT INTO #T(Total, DbName)
SELECT count(1) Total, ''?'' DbName
FROM ?.dbo.Users
END
'
SELECT *
FROM #T
--
-- WHERE DbName LIKE '%SOMECONDITION%'
To get the documentation you could execute: EXEC sp_helptext sp_msforeachdb
The following would also give you your desired results without creating a temp table:
declare
#sql varchar(max) = ''
, #maxid int = (select max(database_id) from sys.databases)
select #sql = #sql +
'select '''+name+''' DatabaseName, count(*) [Count] from '+quotename(name)+'.[dbo].[User]'+char(10)+ case when database_id = #maxid then '' else 'union all' end+char(10)
from sys.databases
where name not in ('master','model','msdb','tempdb')
order by database_id
print (#sql)
exec (#sql)
Note: You need to exclude databases that do not have the User Table in the database in the where clause, where I excluded the system databases...
Results will look like this before executing the Dynamic SQL:
For security reasons, I removed the actual Database Names on my machine...

How to get row count from Different Databases. Database Names, Schema Names and Table Names, stored in SQL Table

I have table that contains Database, Schema, and Table Name. I would like to count the row for each rows using group by for defined column in Same Table.
DECLARE #WeeklyRowCount TABLE
(
db VARCHAR(50)
,sch VARCHAR(15)
,Tb VARCHAR(100)
,col VARCHAR(50)
)
DECLARE #cmd VARCHAR(MAX) = (
SELECT ' UNION ALL SELECT COUNT(*) AS C, DATE_STAMP,'''
+ QUOTENAME(sch) + '.' + QUOTENAME(tb)
+ ''' AS T FROM ' + QUOTENAME(db) + '.' + QUOTENAME(sch) + '.' + QUOTENAME(tb) + 'GROUP BY col'
FROM #WeeklyRowCount )
SELECT COUNT(*) AS C, col ,'Table name' AS T FROM db.sch.tb GROUP BY col
I have tried to use dynamic SQL but due to limitation of 8000 character, full query is not showing up.
You can use undocumented stored procedure sp_msforeachtable to run against each table in the database, to get the row count. But, as it is undocumented stored procedure, in future, it might be removed.
From your question, I understand you want rowcount at table level. The below code generates row count at table level and inserts into table.
CREATE table WeeklyRowCount
(
db VARCHAR(50)
,sch VARCHAR(15)
,Tb VARCHAR(120)
,rcnt VARCHAR(50)
)
exec sp_MSforeachtable ' INSERT INTO WeeklyRowCount(db,sch,tb,col) SELECT db_name() as db,OBJECT_SCHEMA_NAME(OBJECT_ID(''?'')) as sch, ''?'' as tb, count(1) as rcnt from ? '
SELECT * FROM WeeklyRowCount
If you want to run it againt different databases, Use three part identifier for the table containing rowcount WeeklyRowcount
USE dbName
GO
CREATE table WeeklyRowCount
(
db VARCHAR(50)
,sch VARCHAR(15)
,Tb VARCHAR(120)
,rcnt VARCHAR(50)
)
USE DbName1
go
exec sp_MSforeachtable ' INSERT INTO dbname.dbo.WeeklyRowCount(db,sch,tb,col) SELECT db_name() as db,OBJECT_SCHEMA_NAME(OBJECT_ID(''?'')) as sch, ''?'' as tb, count(1) as rcnt from ? '
use DbName2
go
exec sp_MSforeachtable ' INSERT INTO dbname.dbo.WeeklyRowCount(db,sch,tb,col) SELECT db_name() as db,OBJECT_SCHEMA_NAME(OBJECT_ID(''?'')) as sch, ''?'' as tb, count(1) as rcnt from ? '
SELECT * FROM dbname.dbo.WeeklyRowCount
For more information about sp_msforeachtable

SQL: Looping through a column, stored the value as a variable, run SQL, then move on to the next line?

I'm currently shifting roles at my job and trying to teach myself some SQL Skills.
Scenario: I'm in charge of 1 database - 10 tables with 10 Primary Keys. Every month, our code team publishes updates to the tables. I am suppose to drop the tables and generate scripts to create the updated tables.
Rather than just drop the old tables and stored procedures, I want to rename my current tables to preserve the structure/data for whatever reason.
In my database, I have an additional table called "TableUpdateList" with 1 column "TableName" and 10 rows - each row containing the name of the updated column (Row 1 = TableName1, Row 2 = TableName2, Row 3 = TableName3)
I would like to be able to "loop" through the TableUpdateList Table and insert each value into a set of SQL statements.
For Example, here are the SQL statements I want to run:
--drop the previous backup table
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_NAME = '*TableName1*'+'_Old') DROP TABLE TableName1_Old
-- rename the current tables to _old
EXEC sp_rename *TableName1*, TableName1_Old;
I'm trying to find a way to scroll through the column of my TableUpdateList and run the above two statements filling in where I've italicized with whatever value is present in that row.
Just taking a wild stab because I think in order to get an answer here, you have to try something so here is my pseudo-code:
Declare #TableNames as List
For i in #TableNames
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_NAME = '*i*'+'_Old') DROP TABLE TableName1_Old
-- rename the current tables to _old
EXEC sp_rename *i*, TableName1_Old;
Oi, thanks in advance for any help or a point in the right direction to where I could do some further reading about the above online.
You can use sp_executesql with CURSORS for such type of work. Here is what i think you need:
Test objects:
CREATE TABLE TableName1 ( ID INT )
GO
CREATE TABLE TableName2 ( ID INT )
GO
CREATE TABLE TableNames ( Name NVARCHAR(MAX) )
GO
INSERT INTO TableNames
VALUES ( 'TableName1' ),
( 'TableName2' )
Script itself:
DECLARE #name NVARCHAR(MAX) ,
#dropStatement NVARCHAR(MAX),
#renameStatement NVARCHAR(MAX)
DECLARE cur CURSOR FAST_FORWARD READ_ONLY
FOR
SELECT Name
FROM dbo.TableNames
OPEN cur
FETCH NEXT FROM cur INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
IF EXISTS ( SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #name + '_Old' )
BEGIN
SET #dropStatement = 'DROP TABLE ' + #name + '_Old'
EXEC sp_executesql #dropStatement
END
SET #renameStatement = 'sp_rename ' + #name + ', ' + #name + '_Old';
EXEC sp_executesql #renameStatement
FETCH NEXT FROM cur INTO #name
END
CLOSE cur
DEALLOCATE cur
After this you should add TableName1 and TableName2 again.
Cursors must be avoided as long as possible.
--Preparing script which would check if the old tables exists. If it does,
--it drops the old table
--e.g. first the value 'Table1' is found in TableUpdateList table.
--Then, Table1_Old is deleted and Table1 is renamed to Table1_Old
SELECT 'DROP TABLE ' + b.name + '_Old; EXEC sp_rename ''' + b.name+ ''', ''' + b.name+ '_Old;''' AS [Action]
INTO #Action
FROM INFORMATION_SCHEMA.TABLES A JOIN TableUpdateList B ON A.TABLE_NAME = b.NAME + '_Old'
DECLARE #sql VARCHAR(8000)
SELECT #sql = COALESCE(#sql + ' ', '') + [Action]
FROM #Action
select #sql
--EXEC (#sql)
First verify the value of variable #sql. Then, uncomment the last line to execute the code.
SQL fiddle

T-Sql getting data from tempdb table

I'm using Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (X64) and I'm trying to make a SELECT statement to a table that have been created like this:
DECLARE #Sql AS VARCHAR(1500)
SET #Sql = 'SELECT 1 AS id, ''123'' AS value INTO #tmp_prueba'
EXECUTE ( #Sql )
SELECT * FROM #tmp_prueba
But I'm noticed that the table not exists
How can I get the data from the table?
The temporary table that you created in #sql is out-of-scope of the outer query.
Here is one way to do what you want:
DECLARE #Sql AS VARCHAR(1500);
SET #Sql = 'SELECT 1 AS id, ''123'' AS value INTO #tmp_prueba;
select * from #tmp_prueba'
create table #tmp_prueba (id int, value varchar(255));
insert into #tmp_prueba
EXECUTE( #Sql );
SELECT * FROM #tmp_prueba
Here are the changes. FIrst, I select everything from the temproary table in the #sql query. Second, I create a temporary table (with the same name in this case) to hold the results. Now, I can insert the results from the execute into the table. Voila! The data is there.
Temp table are created on Tempdb, therefor you can also do this:
SET #Sql = 'SELECT 1 AS id, ''123'' AS value INTO ##tmp_prueba'
EXECUTE ( #Sql )
Select * from tempdb..##tmp_prueba