T-SQL: Select data from all tables reverted by INFORMATION_SCHEMA.TABLES - sql

I need to extract data from all tables that were reverted by following query:
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'ERP_%'
I've tried to execute following query, but without success:
SELECT *
FROM
(SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'ERP_%')
WHERE STATUS = 'XXX'
Looking forward to your assistance.

You may try to generate a dynamic SQL statement and execute it:
-- Declarations
DECLARE #stm nvarchar(max)
SET #stm = N''
-- Dynamic SQL
SELECT #stm = (
SELECT CONCAT(
N'SELECT * FROM ',
QUOTENAME(TABLE_NAME),
N' WHERE [STATUS] = ''XXX''; '
)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'ERP_%'
FOR XML PATH('')
)
-- Execution
PRINT #stm
EXEC sp_executesql #stm

Try this query using dynamic SQL:
declare #sql varchar(max) = '';
select #sql = #sql + 'select * from ' + TABLE_NAME + ' where [status] = ''XXX''; '
from INFORMATION_SCHEMA.TABLES
where TABLE_NAME like 'ERP_%';
exec(#sql);

Related

Dynamic SQL to get rows from information_schema

Let’s say I’m looking for a specific column in my database so I have something like this
SELECT COLUMN_NAME, TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME like ‘%employeeid%’
But I also want to know how many rows each table has, I was told I can do this using Dynamic SQL so I have this now
DECLARE
#tableName NVARCHAR(MAX),
#sql NVARCHAR(MAX),
#colName NVARCHAR(MAX);
DECLARE CUR_TABLE CURSOR FOR
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS
OPEN CUR_TABLE
FETCH NEXT FROM CUR_TABLE
INTO #tableName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #colName = '%employeeid%'
SET #sql = 'SELECT COLUMN_NAME, TABLE_NAME, (SELECT COUNT(*) FROM ' + #tableName +') AS ROWS FROM INFORMATION_SCHEMA.COLUMNS where column_name like ' + ''' + #colName + ''';
FETCH NEXT FROM CUR_TABLE
INTO #tableName
END;
CLOSE CUR_TABLE
DEALLOCATE CUR_TABLE
EXEC sp_executesql #sql
But this doesn't work, What I'm trying to do is query a table with the column I am looking for, with the table name, and number of rows in the table.
How can I fix this?
You can make use of SQL Server's dynamic management views to quickly obtain the row counts*.
Find all tables with a column named 'MyColumn' and their current rows:
select Schema_Name(t.schema_id) schemaName, t.name TableName, s.row_count
from sys.columns c
join sys.tables t on t.object_id = c.object_id
join sys.dm_db_partition_stats s on s.object_id = c.object_id and s.index_id <= 1
where c.name='MyColumn';
* Accurate except for frequently updated tables where there could be some lag
The following uses INFORMATION_SCHEMA, dynamic SQL, and STRING_AGG() to build a query that will return a single result set.
DECLARE #ColumnName sysname = 'ProductID'
DECLARE #Newline VARCHAR(2) = CHAR(13) + CHAR(10)
DECLARE #SqlTemplate NVARCHAR(MAX) =
+ 'SELECT'
+ ' ColumnName = <ColumnNameString>,'
+ ' TableName = <TableSchemaAndNameString>,'
+ ' Rows = (SELECT COUNT(*) FROM <TableSchemaAndName>)'
+ #Newline
DECLARE #UnionSql NVARCHAR(100) = 'UNION ALL ' + #Newline
DECLARE #Sql NVARCHAR(MAX) = (
SELECT STRING_AGG(
REPLACE(REPLACE(REPLACE(
#SqlTemplate
, '<ColumnNameString>', QUOTENAME(C.COLUMN_NAME, ''''))
, '<TableSchemaAndNameString>', QUOTENAME(C.TABLE_SCHEMA + '.' + C.TABLE_NAME, ''''))
, '<TableSchemaAndName>', QUOTENAME(C.TABLE_SCHEMA) + '.' + QUOTENAME(C.TABLE_NAME))
, #UnionSql)
WITHIN GROUP(ORDER BY C.TABLE_SCHEMA, C.TABLE_NAME)
FROM INFORMATION_SCHEMA.TABLES T
JOIN INFORMATION_SCHEMA.COLUMNS C
ON C.TABLE_SCHEMA = T.TABLE_SCHEMA
AND C.TABLE_NAME = T.TABLE_NAME
WHERE T.TABLE_TYPE = 'BASE TABLE' -- Omit views
AND C.COLUMN_NAME = #ColumnName
)
SET #Sql = #Sql + 'ORDER BY Rows DESC, TableName' + #Newline
--PRINT #Sql
EXEC (#Sql)
I generalized it a bit by adding TABLE_SCHEMA so that it could be used with the AdventureWorks database. See this db<>fiddle for a working demo. Also included is equivalent logic that uses FOR XML instead of STRING_AGG for older SQL Server versions.
Assuming that you are using SQL Server, here is a shorthand way using sp_msforeachtable.
DECLARE #ColumnName NVARCHAR(200) = 'ContactID'
CREATE TABLE #T
(
ColumnName NVARCHAR(200),
TableName NVARCHAR(200),
RecordCount INT
)
INSERT INTO #T (ColumnName, TableName)
SELECT
ColumnName = C.COLUMN_NAME,
TableName = '['+C.TABLE_SCHEMA+'].['+C.TABLE_NAME+']'
FROM
INFORMATION_SCHEMA.COLUMNS C
WHERE
C.COLUMN_NAME LIKE '%' + #ColumnName + '%'
EXEC SP_MSFOREACHTABLE 'IF EXISTS(SELECT * FROM #T WHERE TableName = ''?'') UPDATE #T SET RecordCount = (SELECT COUNT(*) FROM ? ) WHERE TableName = ''?'''
SELECT
ColumnName,TableName,
TableType = CASE
WHEN RecordCount IS NULL
THEN 'View'
ELSE 'Table'
END,
RecordCount
FROM
#T
ORDER BY
CASE WHEN RecordCount IS NULL THEN 'View' ELSE 'Table' END
DROP TABLE #T

query by partial column name

I have a
Checklist table and
there is 27 columns named "check1", "check2"..."check27".I would like to get all this values doing a query something like:
SELECT "check*" FROM Checklist;
Is this possible?
Which database? postgres, sqlite, mysql?
If select * is not an option, the most flexible approach is creating a dynamic query. You will first need to get the column names and then build your query:
DECLARE #tableName as varchar(100);
SET #tableName = 'Checklist';
DECLARE #columnList varchar(300);
SELECT #columnList = COALESCE(#columnList + ', ', '') + sc.name
FROM sysobjects so
INNER JOIN syscolumns sc ON so.id = sc.id
WHERE so.name = #tableName
AND sc.name LIKE 'check%'
DECLARE #query as varchar(4000);
SET #query = 'SELECT ' + #columnList + ' FROM ' + #tableName;
EXEC(#query);
The ending #query should contain SELECT check1, check2, check... FROM Checklist.
In Sql Server, this is terrible but you could do it... Building dynamic SQL
check% being your check* in the Select #columns query
DECLARE #columns NVARCHAR(max);
SELECT #columns = STUFF((
SELECT ',' + column_name
FROM INFORMATION_SCHEMA.columns
WHERE table_name = 'Checklist'
AND column_name LIKE 'check%'
FOR XML path('')
), 1, 1, '')
DECLARE #statement nvarchar(max) = 'SELECT ' + #columns + ' FROM Checklist'
EXECUTE sp_executesql #statement
Troll ass answer...
SELECT check1,check2,check3,check4,check5,check6,check7,check8,check9,check10,check11,check12,check13,check14,check15,check16,check17,check18,check19,check20,check21,check22,check23,check24,check25,check26,check27 FROM Checklist;

How to display the table name in a union query

The following script is working well:
DECLARE #SelectClause VARCHAR(100) = 'SELECT id_contato'
,#Query VARCHAR(8000) = ''
SELECT #Query = #Query + #SelectClause + ' FROM ' + TABLE_NAME + ' UNION ALL '
FROM INFORMATION_SCHEMA.TABLES
WHERE (TABLE_NAME LIKE '%zumbi' or TABLE_NAME like '%engajado%')
SELECT #Query = LEFT(#Query, LEN(#Query) - LEN(' UNION ALL '))
EXEC (#Query)
But I need a second column with the table name to identify where the information came from.
How can I do that?
You're utilizing the table_name field already in your query, just need to add it to your SELECT and quote it properly so it comes back as string literal:
DECLARE #SelectClause VARCHAR(100) = 'SELECT id_contato'
,#Query VARCHAR(8000) = ''
SELECT #Query = #Query + #SelectClause + ','''+Table_Name+''' AS Table_Name FROM ' + TABLE_NAME + ' UNION ALL '
FROM INFORMATION_SCHEMA.TABLES
WHERE (TABLE_NAME LIKE '%zumbi' or TABLE_NAME like '%engajado%')
SELECT #Query = LEFT(#Query, LEN(#Query) - LEN(' UNION ALL '))
EXEC (#Query)
Updated quotes, works for me in SQL Server.

How to get count across multiple tables

I am using this code to get ABC count from all tables having 72 table
if I use
declare #SQL nvarchar(max)
declare #Countt bigint
SELECT #SQL = STUFF(( SELECT ' ; SELECT COUNT(ABC) FROM ' + INFORMATION_SCHEMA.TABLES.TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES LEFT OUTER JOIN INFORMATION_SCHEMA.COLUMNS ON INFORMATION_SCHEMA.TABLES.TABLE_NAME = INFORMATION_SCHEMA.COLUMNS.TABLE_NAME where INFORMATION_SCHEMA.TABLES.TABLE_TYPE =N'BASE TABLE' AND INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME =N'ABC'
FOR XML PATH('')),1,2,'')
SET #SQL = #SQL
PRINT #SQL
EXECUTE (#SQL)
but I am getting 72 results one by one but I just want to get sum of all 72 results,for example if ABC have 10 rows in 4 Tables so it should be return 40 please suggest where I am wrong or any other better way
Everyone is right just need to add schema if there is different ones:
declare #SQL nvarchar(max)
declare #Countt bigint
SELECT #SQL = STUFF((
SELECT DISTINCT ' UNION ALL SELECT COUNT(ABC) AS CountAmount FROM ' + INFORMATION_SCHEMA.TABLES.TABLE_SCHEMA + '.' + INFORMATION_SCHEMA.TABLES.TABLE_NAME AS [text()]
FROM INFORMATION_SCHEMA.TABLES
LEFT OUTER JOIN INFORMATION_SCHEMA.COLUMNS
ON INFORMATION_SCHEMA.TABLES.TABLE_NAME = INFORMATION_SCHEMA.COLUMNS.TABLE_NAME
WHERE INFORMATION_SCHEMA.TABLES.TABLE_TYPE =N'BASE TABLE'
AND INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME =N'ABC'
FOR XML PATH('')),1,11,'')
SET #SQL = 'SELECT SUM( CountAmount ) AS TotalSum FROM (' + #SQL + ' ) AS T '
PRINT #SQL
EXECUTE (#SQL)
declare #SQL nvarchar(max)
declare #Countt bigint
SELECT #SQL = STUFF(( SELECT ' UNION ALL SELECT COUNT(ABC) AS noCount FROM ' + INFORMATION_SCHEMA.TABLES.TABLE_NAME FROM INFORMATION_SCHEMA.TABLES LEFT OUTER JOIN INFORMATION_SCHEMA.COLUMNS ON INFORMATION_SCHEMA.TABLES.TABLE_NAME = INFORMATION_SCHEMA.COLUMNS.TABLE_NAME where INFORMATION_SCHEMA.TABLES.TABLE_TYPE =N'BASE TABLE' AND INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME =N'ABC' FOR XML PATH('')),1,10,'')
SET #SQL = 'SELECT COUNT(*) FROM (' + #SQL + ')A'
PRINT #SQL
EXECUTE (#SQL)
You need to use an aggregate function and group your results. So if Ive read your sql correctly, group by INFORMATION_SCHEMA.TABLES.TABLE_NAME
Use a cursor and iterate over each table one by one. When you generate your dynamic sql string, select the results into a variable like so:
select #TableCount = Count(ABC) From SomeTable
set #TotalCount = #Totalcount + #TableCount

How to use EXEC or sp_executeSQL without looping in this case?

Environment: SQL Server 2005/2008,
pubs database
I have inserted into a table variable a set of data as shown below using information_schema tables.
Now I would like to update the flag column based on the result of executing the query in the column dSQL. I was able to update using loops/cursor and then used sp_executeSQL to
update the column and then update flag column later. But is there an alternate set-based way to do this without looping through all individual rows?
use pubs
go
declare #dsql Nvarchar(max)='', #tablename varchar(100), #colname varchar(100)
declare #t table (
TABLE_NAME varchar(100),
COLUMN_NAME varchar(100)
)
insert into #t
select distinct t.TABLE_NAME, c.COLUMN_NAME
from information_Schema.tables t
inner join
information_Schema.columns c
on t.TABLE_CATALOG = c.TABLE_CATALOG
where t.TABLE_SCHEMA = c.TABLE_SCHEMA
and t.TABLE_TYPE = 'BASE TABLE'
and c.DATA_TYPE = 'varchar'
select *, Dsql = 'select ' + COLUMN_NAME + ' from ' + TABLE_NAME + ' WHERE '
+ COLUMN_NAME + ' = ''Menlo Park''', '' as Flag
FROM #t
GO
I had an idea to create a function and call the function for each row to execute individual query statement but calling the function for each record might be a performance hit.
It's a loop or a function as you suggested (which is really a loop anyway).
Not possible, I made a script like it earlier.
declare #searchvalue varchar(100)
set nocount off
set #searchvalue = 'Hello world'
create table #tt (table_name varchar(64), column_name varchar(64), count int)
select * into #t from
(
select 'select ''' + a.table_name + ''' ''table_name'',''' + a.column_name + ''' ''column_name'', count(*) count from [' + a.table_name +'] where [' +a.column_name+']='''+#searchvalue +'''' + ' group by ['+ a.column_name+']' sqlstring
from INFORMATION_SCHEMA.COLUMNS a
join
INFORMATION_SCHEMA.TABLES b
on a.table_name = b.table_name
and b.table_type = 'base table'
where data_type = 'varchar'
) a
--loop cursor
Declare #sqlstring as nvarchar(500)
Declare SqlCursor CURSOR FAST_FORWARD FOR
SELECT sqlstring FROM #t
OPEN SqlCursor
FETCH NEXT FROM SqlCursor
INTO #sqlstring
WHILE ##FETCH_STATUS = 0
BEGIN
insert #tt
exec(#sqlstring)
FETCH NEXT FROM SqlCursor
INTO #sqlstring
END
CLOSE SqlCursor
DEALLOCATE SqlCursor
select * from #tt
drop table #tt
drop table #t
Use what you want
This is an old question, but I'd like to add a different answer all the same.
Try the following script (no cursor, no loop (according to execution plan)): (tested in MS SQL 2012)
-- Setting up test data/code
SELECT N'SELECT * FROM INFORMATION_SCHEMA.COLUMNS AS C' T
INTO #Code
UNION ALL
SELECT N'SELECT * FROM INFORMATION_SCHEMA.TABLES AS T'
-- Variable to hold the selected queries, seperated by CrLf. You can also add a "GO" or ";"
DECLARE #SQL NVARCHAR(MAX) = CHAR(13) + CHAR(10)
-- Concatenate the selected queries together into the variable
SELECT #SQL = #SQL + CHAR(13) + CHAR(10) + C.T
FROM #Code AS C
-- Execute
EXEC sys.sp_executesql #SQL
-- Clean up
DROP TABLE #Code