Run a query in every table that contains a specific column - sql-server

I run this query to get all the tables that include a specific column name
SELECT COLUMN_NAME, TABLE_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '%myColumn%'
Then, for every single table, I want to run a query like this one:
SELECT * FROM table WHERE myColumn = xxx
Is there any way to do it automatically and run the second query to all the tables from the first query?
I have a fairly big database and I want to check if there is anywhere stored something about the specific Id on myColumn. And this column is used in about 200 tables.

I guess you need to use dynamic query for this. in this I saved the Schema result in a table variable and then loop through them to generate the required query. please try the below:
DECLARE #Template varchar(max)='SELECT * FROM [TABLE_NAME] WHERE [COLUMN_NAME] = ''xxx''';
DECLARE #CMD varchar(max);
DECLARE #id int=1, #TABLE_NAME varchar(255), #COLUMN_NAME varchar(255)
declare #Table table(id int identity(1,1), COLUMN_NAME varchar(255), TABLE_NAME varchar(255))
INSERT INTO #Table (TABLE_NAME, COLUMN_NAME)
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '%Label%'
SELECT #id=ID, #TABLE_NAME = TABLE_NAME, #COLUMN_NAME = COLUMN_NAME FROM #Table WHERE ID = #id
While ##ROWCOUNT>0 BEGIN
SET #CMD = REPLACE(#Template, '[TABLE_NAME]', #TABLE_NAME)
SET #CMD = REPLACE(#CMD, '[COLUMN_NAME]', #COLUMN_NAME)
Print #cmd
EXEC (#CMD)
SELECT #id=ID, #TABLE_NAME = TABLE_NAME, #COLUMN_NAME = COLUMN_NAME FROM #Table WHERE ID = #id + 1
End

You could do this as follows. The script builds all the SELECT statements in a VARCHAR and then executes dynamically. Works when you for integers as well as varchars.
DECLARE #col_name SYSNAME='myColumn';
DECLARE #expected_value NVARCHAR(256)='xxx';
DECLARE #sel_stmts NVARCHAR(MAX) = (
SELECT
';SELECT '+
'* '+
'FROM '+
QUOTENAME(t.TABLE_SCHEMA)+'.'+QUOTENAME(t.TABLE_NAME) +
'WHERE '+
QUOTENAME(c.COLUMN_NAME)+'='''+REPLACE(#expected_value,'''','''''')+''''
FROM
INFORMATION_SCHEMA.TABLES AS t
INNER JOIN INFORMATION_SCHEMA.COLUMNS AS c ON
c.TABLE_SCHEMA=t.TABLE_SCHEMA AND
c.TABLE_NAME=t.TABLE_NAME
WHERE
t.TABLE_TYPE='BASE TABLE' AND
c.COLUMN_NAME LIKE '%'+#col_name+'%'
FOR
XML PATH('')
)+';';
--SELECT #sel_stmts; -- review
EXEC sp_executesql #sel_stmts; -- execute it

I made a couple changes to Ahmed Saeed's answer that were helpful for me so posting them here
Adding the schema name for dbs with more than one schema
Adding extra [] around the schema/db names in case one of those names is also a keyword
Printing the tablename with the results
DECLARE #Template varchar(max)='SELECT ''[TABLE_NAME]'' as TableName, * FROM [[DBSCHEMA_NAME]].[[TABLE_NAME]] WHERE [COLUMN_NAME] = ''xxx''';
DECLARE #CMD varchar(max);
DECLARE #id int=1, #DBSCHEMA_NAME varchar(255), #TABLE_NAME varchar(255), #COLUMN_NAME varchar(255)
declare #Table table(id int identity(1,1), COLUMN_NAME varchar(255), TABLE_NAME varchar(255), DBSCHEMA_NAME varchar(255))
INSERT INTO #Table (TABLE_NAME, COLUMN_NAME, DBSCHEMA_NAME)
SELECT TABLE_NAME, COLUMN_NAME, TABLE_SCHEMA
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '%colname%'
SELECT #id=ID, #DBSCHEMA_NAME = DBSCHEMA_NAME, #TABLE_NAME = TABLE_NAME, #COLUMN_NAME = COLUMN_NAME FROM #Table WHERE ID = #id
While ##ROWCOUNT>0 BEGIN
SET #CMD = REPLACE(#Template, '[TABLE_NAME]', #TABLE_NAME)
SET #CMD = REPLACE(#CMD, '[COLUMN_NAME]', #COLUMN_NAME)
SET #CMD = REPLACE(#CMD, '[DBSCHEMA_NAME]', #DBSCHEMA_NAME)
Print #cmd
EXEC (#CMD)
SELECT #id=ID, #DBSCHEMA_NAME = DBSCHEMA_NAME, #TABLE_NAME = TABLE_NAME, #COLUMN_NAME = COLUMN_NAME FROM #Table WHERE ID = #id + 1
End

Related

Way to select all columns from table and near each one the same column name with prefix?

Let's say I have a table with the following columns:
"col1", "col2", "col3", "new_col1", "new_col2", "new_col3" ...
I want to display the columns in the following way:
select col1, new_col1, col2, new_col2, col3, new_col3 ...
Is there a select command/keyboard shortcut that I can do that without copy each column in the select command
Thank you
I have a custom procedure mapped to Ctrl+8 shortcut.
It's something like that:
CREATE or ALTER PROC dbo.utl_get_select(
#table sysname,
#alias varchar(10) = 'v'
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #query varchar(max) = 'SELECT';
SELECT #alias = ISNULL(#alias, 'v')
SELECT #query = #query + ' ' + #alias + '.' + QUOTENAME(c.name)+','
FROM sys.objects t
JOIN sys.columns c ON c.object_id = t.object_id
WHERE t.name = #table
ORDER BY c.column_id ASC;
SELECT #query = LEFT(#query, LEN(#query)-1) + ' ';
SELECT #query + 'FROM dbo.' + #Table + ' ' + #alias;
END;
We could also use STRING_AGG in SQL Server 2017 or newer.
You can also compare columns names to achieve some customised order.
And the result for EXEC dbo.utl_get_select 'users'
SELECT v.[id], v.[login], v.[email], v.[name], v.[last_name] FROM dbo.users v
Here is a script for Insert and Select
DECLARE #String nvarchar(max)='',#Column nvarchar(100),#Insert nvarchar(max), #Select nvarchar(max),#TBL_NAME nvarchar(150)
SET #TBL_NAME = 'TestTable'
DECLARE CURS CURSOR LOCAL FAST_FORWARD FOR
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TBL_NAME
OPEN CURS
FETCH NEXT FROM CURS INTO #Column
WHILE ##FETCH_STATUS=0
BEGIN
SET #String = #String +'['+#Column+'],'+'['+#Column+'_NEW],'
FETCH NEXT FROM CURS INTO #Column
END
CLOSE CURS
DEALLOCATE CURS
SET #String = SUBSTRING(#String,1,LEN(#String)-1)
SET #Insert = 'INSERT INTO ['+#TBL_NAME+'] ('+#String+')'
SET #Select = 'SELECT '+#String
Select #Insert,#Select

How to select Columns using parameters in report builder

In report builder can we select columns using parameters.
Example : select #field, column2, column3 from table_name
where #field is a parameter.
Also is there any way to do this:
select #field, column2, sum(column3) OVER (PARTITION BY #field) from table_name
This can only be done using dynamic sql:
CREATE PROCEDURE COLUMNRETURN
#ColumnName as nvarchar(100)
as
declare #sql as nvarchar(max)
set #sql = 'Select [' + #ColumnName + '] from [mytable]'
exec (#sql)
EXEC COLUMNRETURN 'mycolumn'

SQL Server query to select all columns of a certain type and also show its max values

I am using SQL Server 2012.
The first part of my query is already answered in this thread. But I also want a second column that will show the corresponding maximum value of that column in its corresponding table.
I have tried this approach: use a function that takes in table name and column name as parameter and return the max value. But it is illegal to use dynamic SQL from a function. Moreover, i cannot seem to call a function from within a SELECT query.
I have also tried using stored procedure, but i cannot figure out how to call it and use it. Please suggest alternative ways to achieve this.
I am new to SQL Server.
Thanks
I think the easiest solution would be stored procedure. As far as I know:
Dynamic SQL can't be placed in functions
Dynamic SQL can't be place in OPENROWSET
I addition, if you write such procedure:
Beware of names containing spaces, qoutes (SQL injection possible)
MAX(column) on non-Indexed columns would require full scan (can be very slow)
Table and column names can be duplicated (placed in differend schemas)
Id duplicates and performance is not a problem, take a look at the following snippet:
CREATE PROC FindMaxColumnValues
#type sysname = '%',
#table sysname = '%'
AS
DECLARE #result TABLE (TableName sysname, ColumnName sysname, MaxValue NVARCHAR(MAX))
DECLARE #tab sysname
DECLARE #col sysname
DECLARE cur CURSOR FOR
SELECT TABLE_NAME TableName, COLUMN_NAME [Column Name]
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE LIKE #type and TABLE_NAME LIKE #table
OPEN cur
FETCH NEXT FROM cur INTO #tab, #col
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #sql nvarchar(MAX) = 'SELECT '+QUOTENAME(#tab,'''')+' [TableName], '+QUOTENAME(#col, '''')+' [ColumnName], MAX('+QUOTENAME(#col)+') FROM '+QUOTENAME(#tab)
INSERT INTO #result EXEC(#sql)
FETCH NEXT FROM cur INTO #tab, #col
END
CLOSE cur
DEALLOCATE cur
SELECT * FROM #result
Samples:
--MAX of INT's
EXEC FindMaxColumnValues 'INT'
--MAX of INT's in tables matching 'TestTab%'
EXEC FindMaxColumnValues 'INT', 'TestTab%'
--MAX of ALL columns
EXEC FindMaxColumnValues
Results:
TableName ColumnName MaxValue
IdNameTest ID 2
TestTable ID 5
TestTable Number 3
TableName ColumnName MaxValue
TestTable ID 5
TestTable Number 3
TableName ColumnName MaxValue
UpdateHistory UpdateTime 2016-07-14 12:21:37.00
IdNameTest ID 2
IdNameTest Name T2
TestTable ID 5
TestTable Name F
TestTable Number 3
You can use the below SP and enhance it per your Need,
CRETE PROCEDURE Getmaxtablecolval
AS
BEGIN
CREATE TABLE #t
(
tablename VARCHAR(50),
columnname VARCHAR(50),
id INT,
counts INT
)
INSERT INTO #t
SELECT table_name [Table Name],
column_name [Column Name],
NULL,
NULL
FROM information_schema.columns
WHERE data_type = 'INT'
BEGIN TRAN
DECLARE #id INT
SET #id = 0
UPDATE #t
SET #id = id = #id + 1
COMMIT TRAN
DECLARE #RowCount INT
SET #RowCount = (SELECT Count(0)
FROM #t)
DECLARE #I INT
SET #I = 1
DECLARE #Counter INT
DECLARE #TName VARCHAR(50)
DECLARE #CName VARCHAR(50)
DECLARE #DynamicSQL AS VARCHAR(500)
WHILE ( #I <= #RowCount )
BEGIN
SELECT #TName = tablename
FROM #t
WHERE id = #I
SELECT #CName = columnname
FROM #t
WHERE id = #I
SET #DynamicSQL = 'Update #T Set Counts = '
+ '(Select ISNull(Max(' + #CName + '), 0) From '
+ #TName + ') Where Id = '
+ CONVERT(VARCHAR(10), #I)
--PRINT #DynamicSQL
EXEC (#DynamicSQL)
SET #I = #I + 1
END
SELECT *
FROM #t
END
go
Getmaxtablecolval
You can create a procedure out of this:
CREATE PROCEDURE GET_COLUMNS_WITH_MAX_VALUE
#COLUMN_TYPE NVARCHAR(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- DUMMY VARIABLE TO COPY STRUCTURE TO TEMP
DECLARE #DUMMY TABLE
(
TABLE_NAME NVARCHAR(50),
COLUMN_NAME NVARCHAR(50),
MAX_VALUE NVARCHAR(MAX)
)
-- CREATE TEMP TABLE FOR DYNAMIC SQL
SELECT TOP 0 * INTO #TABLE FROM #DUMMY
INSERT INTO #TABLE
(TABLE_NAME, COLUMN_NAME)
SELECT TABLE_NAME, COLUMN_NAME
FROM information_schema.columns where data_type = #COLUMN_TYPE
DECLARE #TABLE_NAME VARCHAR(50) -- database name
DECLARE #COLUMN_NAME VARCHAR(256) -- path for backup files
DECLARE db_cursor CURSOR FOR
SELECT TABLE_NAME, COLUMN_NAME
FROM #TABLE
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #TABLE_NAME, #COLUMN_NAME
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #SQL NVARCHAR(MAX) = 'UPDATE #TABLE SET MAX_VALUE = (SELECT MAX([' + #COLUMN_NAME + ']) FROM [' + #TABLE_NAME + ']) '
+ 'WHERE [COLUMN_NAME] = ''' + #COLUMN_NAME + ''' AND TABLE_NAME = ''' + #TABLE_NAME + '''';
PRINT #SQL
EXEC (#SQL)
FETCH NEXT FROM db_cursor INTO #TABLE_NAME, #COLUMN_NAME
END
CLOSE db_cursor
DEALLOCATE db_cursor
SELECT * FROM #TABLE
DROP TABLE #TABLE
END
GO
Usage:
EXEC GET_COLUMNS_WITH_MAX_VALUE 'INT'
Results:
TABLE1 ID 50
TABLE2 ID 100
TABLE3 CarID 20
TABLE4 StudentID 30

WITH statement in dynamic sql

I need to store a query as a stored procedure in SQL Server.
I need also to pass parameters which define tablenames and column names.
This is the query I owuld like to have, I tried to store it in a string and then EXECUTE it but without success, ho can I solve this?
CREATE PROCEDURE sp_selectAllParents #id int, #tableid varchar(30), #tablename varchar(30)
AS BEGIN
SET NOCOUNT ON;
WITH ct AS (
SELECT * FROM #tablename t WHERE #tableid = #id
UNION ALL
SELECT t.* FROM #tablename t JOIN ct ON t.parentId = ct.#tableid
)
SELECT * FROM #tablename t WHERE #tableid NOT IN (SELECT #tableid FROM ct)
END
EDIT:
my attempt was:
DECLARE #sql varchar(255)
SET #sql = 'WITH ct AS (SELECT * FROM #tablename t WHERE #tableid = #id UNION ALL SELECT t.* FROM #tablename t JOIN ct ON t.parentId = ct.#tableid) SELECT * FROM #tablename t WHERE #tableid NOT IN (SELECT #tableid FROM ct)'
EXEC(#sql)
As I already in the comment section, it is a bad idea to do this. You should really rethink your solution.
The Stored Procedure would have to look like this:
CREATE PROCEDURE selectAllParents #id int, #tableid sysname, #tablename sysname
AS
BEGIN
SET NOCOUNT ON;
-- Guards against SQL Injection attacks (replace ' with '')
SET #tableid=REPLACE(#tableid,'''','''''');
SET #tablename=REPLACE(#tablename,'''','''''');
DECLARE #stmt NVARCHAR(4000);
SET #stmt=
';WITH ct AS ('+
'SELECT * FROM ' + QUOTENAME(#tablename) + ' t WHERE ' + QUOTENAME(#tableid) + '= #id ' +
'UNION ALL ' +
'SELECT t.* FROM ' + QUOTENAME(#tablename) + ' t JOIN ct ON t.parentId = ct.' + QUOTENAME(#tableid) +
')'+
'SELECT * FROM ' + QUOTENAME(#tablename) +' t WHERE ' + QUOTENAME(#tableid) + ' NOT IN (SELECT ' + QUOTENAME(#tableid) +' FROM ct);';
EXEC sp_executesql
#stmt,
N'#id int',
#id;
END
GO
if your are sending Table name as parameter in that case you need to create dynamic query string. may help below script
CREATE PROCEDURE sp_selectAllParents #id int, #tableid varchar(30), #tablename varchar(30)
AS BEGIN
SET NOCOUNT ON;
SET #query=N'WITH ct AS (
SELECT * FROM #tablename t WHERE #tableid = #id
UNION ALL
SELECT t.* FROM #tablename t JOIN ct ON t.parentId = ct.#tableid
)
SELECT * FROM #tablename t WHERE #tableid NOT IN (SELECT #tableid FROM ct)'
EXECUTE sp_executesql #query, #id,#tablename,#tableid
END

Drop multiple tables with string

I have tables like lg-010-a..., lg-010-ac..., and so on, I have abc database,
I have a command window:
drop table from abc where Table_Name like 'lg-010-%'
Will this drop all the tables starting with lg-010-?
Try something like this:
declare #sql varchar(max)
declare #tablenames varchar(max)
select #tablenames = coalesce(#tablenames + ', ','') + Table_Name from INFORMATION_SCHEMA.TABLES
where Table_Name like ('lg-010-%')
set #sql = 'drop table ' + #tablenames
exec (#sql)
This queries the INFORMATION_SCHEMA.TABLES table to retrieve table names that match your criteria, then concatenates them together into a comma delimited string.
This string is than added to a 'Drop table ' statement and executed.
Drop table can take multiple comma delimited table names.
(I had originally had this query sys.tables but some research revealed that while they are currently equivalent, the Information_Schema method is quaranteed to work in future versions)
Unfortunately you can't do it like that. One way is:
SELECT 'DROP TABLE ' + name FROM sysobjects WHERE name LIKE '%lg-010-a%' AND [type] IN ('P')
This will just print out the DROP TABLE statement for each table - you can then copy and paste this output and run it. You can just put an EXECUTE in the loop instead of the PRINT, but I've done it this way so you can see what's going on/check the output first.
I had an issue where the accepted answer was not doing anything. I discovered that I had to add the prefix name of the database to the code to get it to work. If your tables are not dbo.tablename try this.
declare #sql varchar(max)
declare #tablenames varchar(max)
SELECT
#tablenames = COALESCE(#tablenames + ', ','') + 'YourDatabaseName.' + Table_Name
FROM
INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME LIKE 'AP2%'
AND (RIGHT(TABLE_NAME, 6) < 201708)
SET #sql = 'drop table ' + #tablenames
EXEC (#sql)
GO
Unfortunately you can't do it like that.
One way is:
DECLARE #TableName NVARCHAR(128)
SELECT TOP 1 #TableName = TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'lg-010-%'
ORDER BY TABLE_NAME ASC
WHILE (##ROWCOUNT > 0)
BEGIN
PRINT 'DROP TABLE [' + #TableName + ']'
SELECT TOP 1 #TableName = TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'lg-010-%'
AND TABLE_NAME > #TableName
ORDER BY TABLE_NAME ASC
END
This will just print out the DROP TABLE statement for each table - you can then copy and paste this output and run it. You can just put an EXECUTE in the loop instead of the PRINT, but I've done it this way so you can see what's going on/check the output first.
CREATE PROCEDURE dbo.drop_MsSqlTables1 #createDate smalldatetime
AS
declare #flag int =1
declare #tname varchar(50)
declare #sql varchar(max)
select row_number() over (order by name) as num, '[dbo].[' + name +']' as table_name into #temp from sys.tables where name like ('EmpInfo_%') and create_date<#createDate
declare #count int = (select count(*) from #temp)
select * from #temp
while #flag <= #count
begin
set #tname = (select table_name from #temp where num = #flag)
set #sql = 'drop table ' + #tname
exec (#sql)
set #flag = #flag+1
end

Resources