Dynamic SQL with table name from a field - sql-server

Is there a way to generate dynamic sql statement, such that the field value from one table participates in a table name being joined?
Here is what I am trying to do:
DECLARE #sql NVARCHAR(MAX) = N''
DECLARE #MainProc NVARCHAR(MAX) = N'dbo.MainProc'
SET #sql += N'SELECT ref.*
FROM sys.dm_sql_referenced_entities (' + #MainProc + N', ''OBJECT'') AS ref
INNER JOIN ' + ref.referenced_database_name + '.sys.objects AS o ON ref.referenced_id = o.object_id AND o.type = ''P''
WHERE ref.referenced_schema_name NOT IN (''system'')'
EXEC sp_executesql #sql
How can the value of ref.referenced_database_name be attached to sys.objects?

Yes with a little refactoring. In your original example you were trying to extract a value from dm_sql_referenced_entities before you had queried it.
DECLARE #sql NVARCHAR(MAX) = N''
DECLARE #MainProc NVARCHAR(MAX) = N'Fact.Account_Load'
/* Builds the sys.Objects query.
* Can return multiple queries.
*/
SELECT
#sql +=
'
SELECT
s.*
FROM
' + QUOTENAME(ref.referenced_database_name) + '.sys.objects AS s
WHERE
s.Object_Id = ' + CAST(ref.referenced_id AS VARCHAR(255)) + '
AND s.Type = ''P''
;
'
FROM
sys.dm_sql_referenced_entities('Fact.Account_Load', 'OBJECT') AS ref
WHERE
ref.referenced_database_name IS NOT NULL
GROUP BY
ref.referenced_database_name,
ref.referenced_id
;
-- Executes dynamic query.
EXECUTE(#sql);

Related

How to Select tables names to this query

I want to select phone numbers from all tables in my databese and names of these tables too. I write a query that shows me all phone_numbers but I dont't know how to select table name to each phone number. This is my query:
DECLARE #SQL AS VarChar(MAX)
SET #SQL = ''
SELECT #SQL = #SQL + 'SELECT phone_number FROM ' + TABLE_SCHEMA + '.[' + TABLE_NAME + ']' + CHAR(13)
FROM INFORMATION_SCHEMA.TABLES where table_name in (select table_name
from information_schema.columns
where column_name = 'phone_number'
)
You can simply add the table name as a constant to the SELECT clause. But, I presume you're going to want to run this query, which means you have a few more things to change:
You're probably going to want sp_executesql, which requires a Unicode variable. So, you need to DECLARE #SQL NVARCHAR(MAX).
Do you want one result set or multiple result sets? I'm guessing you want all the results in one result set, which means you're going to want to use UNION ALL between the parts of the query.
So, try something like this:
DECLARE #sql NVARCHAR(MAX)
SET #sql = N'SELECT '''' AS table_name, '''' AS phone_number FROM [dbo].[SomeTable] WHERE 1 = 0'
DECLARE #table_name SYSNAME
DECLARE cur CURSOR LOCAL FAST_FORWARD FOR
SELECT table_name
FROM INFORMATION_SCHEMA.columns
WHERE column_name = 'phone_number'
OPEN cur
FETCH NEXT FROM cur INTO #table_name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = #sql + N' UNION ALL SELECT ''' + #table_name + N''', phone_number FROM [' + #table_name + N']'
FETCH NEXT FROM cur INTO #table_name
END
CLOSE cur
DEALLOCATE cur
EXEC sp_executesql #sql
When I used [dbo].[SomeTable], just use some table that you know exists. You would also need to modify the query if you want fully-qualified table names, but the above should get you started.
Another solution without CURSOR. You could combine each query with UNION like this.
--SELECT DISTINCT phone_number FROM dbo.Course c
DECLARE #sql nvarchar(max) = ''
SELECT #sql = #sql + N' SELECT DISTINCT phone_number, '''+ s.name + '.' + t.name + ''' AS TableName
FROM '+ s.name + '.' + t.name + Char(13) + ' UNION' + char(13)
FROM sys.tables t
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
INNER JOIN sys.columns c ON c.object_id = t.object_id
WHERE c.name ='phone_number'
IF(#sql != '')
BEGIN
SET #sql = LEFT(#sql,len(#sql) - 6) -- remove last UNION
PRINT #sql
-- execute sql
EXEC sp_executesql #sql
END
I also add column TableName: Table of phone_number
If you want TableName if the first column then change it
SELECT #sql = #sql + N' SELECT DISTINCT '''+ s.name + '.' + t.name + ''' AS TableName, phone_number
FROM '+ s.name + '.' + t.name + Char(13) + ' UNION' + char(13)

Select any column with respect to cell containing

I have a table named a. Some cells containing a string 'Empty' in many columns. I want to find this columns. Can you help me?.
Try this dynamic query, it will check all the columns with character data and list the columns which has the word 'Empty'.
DECLARE #SearchText VARCHAR(50) = 'Empty'
DECLARE #sql NVARCHAR(MAX) = 'SELECT '
SELECT #sql = #sql + 'MAX(CASE WHEN ' + c.COLUMN_NAME + ' LIKE ''%'+ #SearchText +'%'' THEN ''' + c.COLUMN_NAME +''' ELSE '''' END) + '','' + '
FROM INFORMATION_SCHEMA.COLUMNS c WHERE c.TABLE_SCHEMA = 'dbo' and c.TABLE_NAME = 'a'
AND c.DATA_TYPE IN ('varchar','char','nvarchar','nchar','sysname')
SET #sql = #sql + ''''' FROM dbo.a'
EXEC sys.sp_executesql #sql
Hope this helps
Use the LIKE operator:
SELECT a.*
FROM a
WHERE a.col1 LIKE '%Empty%' OR a.col2 LIKE '%Empty%' OR ...
In sql server you can get object id of table then using that object id you can fetch columns. In that case it will be as below:
Step 1: First get Object Id of table
select * from sys.tables order by name
Step 2: Now get columns of your table and search in it:
select * from a where 'Empty' in (select name from sys.columns where object_id =1977058079)
Note: object_id is what you get fetch in first step for you relevant table
You can do it using unpivot with an help of dynamic query , here i have done below an working sample for you , there might be some modification you might have to do to put the below psedo code with your working .
Sample table structure been used :
create table ColTest
(
name1 varchar(10),
name2 varchar(10),
name3 varchar(10),
name4 varchar(10)
)
insert into ColTest values ('sdas','asdasda','ewrewr','erefds')
insert into ColTest values ('sdas','asdasda','EMPTY','erefds')
insert into ColTest values ('EMPTY','asdasda','ewrewr','erefds')
DECLARE #table_name SYSNAME
SELECT #table_name = 'ColTest'
DECLARE #tmpTable SYSNAME
SELECT #tmpTable = 'ColTest2'
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = '
SELECT * into
' + #tmpTable + '
FROM ' + #table_name + '
UNPIVOT (
cell_value FOR column_name IN (
' + STUFF((
SELECT ', [' + c.name + ']'
FROM sys.columns c WITH(NOLOCK)
LEFT JOIN (
SELECT i.[object_id], i.column_id
FROM sys.index_columns i WITH(NOLOCK)
WHERE i.index_id = 1
) i ON c.[object_id] = i.[object_id] AND c.column_id = i.column_id
WHERE c.[object_id] = OBJECT_ID(#table_name)
AND i.[object_id] IS NULL
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') + '
)
) unpiv'
PRINT #SQL
EXEC sys.sp_executesql #SQL
select * from ColTest2 where cell_value = 'EMPTY'
I'd suggest dynamic SQL
--First you set the variable #TableName to your actual table's name.
DECLARE #TableName VARCHAR(100)='a';
--The following statement will create a list of all columns with a data type containing the word "char" (others should not hold the value Empty)
DECLARE #ColList VARCHAR(MAX)=
STUFF(
(
SELECT ' OR ' + COLUMN_NAME + ' LIKE ''%empty%'''
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME=#TableName AND DATA_TYPE LIKE '%char%'
FOR XML PATH('')
),1,4,'');
--This statement builds a command
DECLARE #cmd VARCHAR(MAX)=
(
SELECT 'SELECT * FROM [' + #TableName + '] WHERE ' + #ColList
);
--Here you can see the command
PRINT #cmd;
--And here it is executed
EXEC(#cmd);

Find blank cells in entire table without specifying all column names in OR condition

There are 190 columns in my table and I trying to list out empty or blank cells. Already i know to check this condition in where clause by using OR, but for no. of 190 columns it seems very long work....So I Tried following query in order to list out null values but when i alter the query according to my criteria by changing in the place of 'IS NULL' as '' to get empty cells it doesn't works
DECLARE #tb NVARCHAR(255) = N'dbo.[Sales_Five_Years]';
DECLARE #sql NVARCHAR(MAX) = N'SELECT * FROM ' + #tb
+ ' WHERE 1 = 0';
SELECT #sql += N' OR ' + QUOTENAME(name) + ' IS NULL'
FROM sys.columns
WHERE [object_id] = OBJECT_ID(#tb);
EXEC sp_executesql #sql;
Please guide me, Thanks in advance
Try this
SELECT #sql += N' OR convert(varchar(50),' + Quotename(name) + ')='''''
FROM sys.columns
WHERE [object_id] = Object_id(#tb);
check this example
i didn't get any error.
CREATE TABLE pr1
(
col VARCHAR(50),
col1 VARCHAR(50)
)
INSERT INTO pr1
SELECT '',NULL
UNION
SELECT NULL,'a'
UNION
SELECT 'b','a'
SELECT #sql += N' OR convert(varchar(50),' + Quotename(name) + ')='''''
FROM sys.columns
WHERE [object_id] = Object_id(#tb);
PRINT #sql
EXEC Sp_executesql
#sql;

SQL Server - find all tables in database with unique ID value

I want to find out all the tables in the database (in SQLServer) that has the column IDName with particular value 'SAM', like so IDName='SAM'. So my initial apporach was create a table with all the tables that have the column "IDName" (since not all the tables in the database has this column. Then i was thinking of going through each table to see which tables match the IDName='SAM' - This is where i'm stuck. I'm pretty sure there is a lot faster way of doing this too but im not too familiar with database query coding. Anything will help Thanks!
select * into tmp from
(
SELECT SO.NAME AS TableName, SC.NAME AS ColumnName
FROM dbo.sysobjects SO INNER JOIN dbo.syscolumns SC ON SO.id = SC.id
WHERE sc.name = 'IDName' and SO.type = 'U'
) tablelist
So if I go Select * from tmp, I get the list of tables that have the column "IDName". Now I have to go through each one of that list and see if they have "IDName = 'Sam'" if they do add it to the output table. In the end I want to see all the names of the tables from the database that has the IDName 'Sam'.
DECLARE #sql AS varchar(max) = '';
DECLARE #ColumnName AS varchar(100) = 'IDName'
DECLARE #ResultQuery AS varchar(max) = 'SELECT ''#TableName'' AS TableName ' +
' ,#ColumnName ' +
'FROM #TableName ' +
'WHERE #ColumnName = ''SAM''';
SET #ResultQuery = REPLACE(#ResultQuery, '#ColumnName', QUOTENAME(#ColumnName));
WITH AllTables AS (
SELECT SCHEMA_NAME(Tables.schema_id) AS SchemaName
,Tables.name AS TableName
,Columns.name AS ColumnName
FROM sys.tables AS Tables
INNER JOIN sys.columns AS Columns
ON Tables.object_id = Columns.object_id
WHERE Columns.name = #ColumnName
)
SELECT #sql = #sql + ' UNION ALL ' +
REPLACE(#ResultQuery, '#TableName', QUOTENAME(TableName)) + CHAR(13)
FROM AllTables
SET #sql = STUFF(#sql, 1, LEN(' UNION ALL'), '');
--PRINT #sql;
SET #sql =
'WITH AllTables AS ( ' +
#sql +
') ' +
'SELECT DISTINCT TableName ' +
'FROM AllTables ';
EXEC (#sql)

Find table name in all objects of all databases

I have a system with multiple databases and client applications. All databases are at one SQL Server instance. They have been developed by different people at different time. So if some error occur it is pritty hard to find in which procedure or trigger the data was modified.
Now I use this script, which I found on this site:
SELECT DISTINCT ISNULL(sd.referenced_schema_name+'.','')+ OBJECT_NAME(sd.referenced_id)TableName,
OBJECT_NAME(sd.referencing_id)Ref_Object,
CASE WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsUserTable')= 1
THEN'Table'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsTableFunction')= 1
THEN'Function'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsTableFunction')= 1
THEN'Function'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsScalarFunction')=1
THEN'Function'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsTrigger')= 1
THEN'Trigger'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsView')= 1
THEN'View'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsUserTable')= 1
THEN'Table'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsProcedure')= 1
THEN'Procedure'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsIndexed')= 1
THEN'Index'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsForeignKey')= 1
THEN'ForeignKey'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsPrimaryKey')= 1
THEN'PrimaryKey'
END AS Ref_Object_Name
FROM sys.sql_expression_dependencies SD
INNER JOIN sys.objects obj
ON obj.object_id=sd.referenced_id
WHERE obj.is_ms_shipped= 0
and referenced_id=object_id('TABLE_NAME') /*Where one can Replace table Name*/
AND obj.type_desc='USER_TABLE'
ORDER BY TableName,Ref_Object,Ref_Object_Name
But this script seems to work only for the database to which the table belong.
I want to get for a specified table name (or even better for an object) list of all objects of all databases in which the specified table name met:
Database_Name SchemaName ObjectName ObjectKind
Thanks.
DECLARE #table_name SYSNAME = N'%';
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += 'SELECT DISTINCT Database_Name = ''' + QUOTENAME(name) + ''',
COALESCE(sd.referenced_schema_name +''.'', '''')+ o.name AS TableName,
r.name AS Ref_Object,
r.type_desc AS Ref_Object_Name
FROM ' + QUOTENAME(name) + '.sys.sql_expression_dependencies AS sd
INNER JOIN ' + QUOTENAME(name) + '.sys.objects AS o
ON o.object_id = sd.referenced_id
INNER JOIN ' + QUOTENAME(name) + '.sys.objects AS r
ON sd.referencing_id = r.object_id
WHERE o.is_ms_shipped = 0
and referenced_id = o.object_id
AND o.type_desc = ''USER_TABLE''
AND o.name LIKE ''' + #table_name + '''
UNION ALL
'
FROM sys.databases
WHERE database_id BETWEEN 5 AND 32766;
SET #sql = LEFT(#sql, LEN(#sql)-11)
+ 'ORDER BY Database_Name, TableName,Ref_Object,Ref_Object_Name';
EXEC sp_executesql #sql;
EDIT
The above will find all the references within each database, but won't find cross-database references. It took a little playing, and the output isn't precisely what you wanted, but I think it makes it more self-explanatory:
DECLARE #table_name SYSNAME = N'%'; -- find all
CREATE TABLE #d
(
db SYSNAME,
[object_id] INT,
sch SYSNAME,
obj SYSNAME,
ref_db NVARCHAR(128),
ref_sch NVARCHAR(128),
ref_obj NVARCHAR(128),
ref_object_id INT,
type_desc SYSNAME
);
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += 'SELECT ''' + QUOTENAME(name) + ''',
d.referencing_id,
QUOTENAME(s.name),
QUOTENAME(o.name),
QUOTENAME(d.referenced_database_name),
QUOTENAME(d.referenced_schema_name),
QUOTENAME(d.referenced_entity_name),
d.referenced_id,
o.type_desc
FROM ' + QUOTENAME(name)
+ '.sys.sql_expression_dependencies AS d
INNER JOIN ' + QUOTENAME(name)
+ '.sys.objects AS o
ON d.referencing_id = o.[object_id]
INNER JOIN '
+ QUOTENAME(name) + '.sys.schemas AS s
ON o.[schema_id] = s.[schema_id]
WHERE d.referenced_entity_name LIKE ''' + #table_name + '''
UNION ALL
'
FROM sys.databases WHERE database_id BETWEEN 5 AND 32766;
SET #sql = LEFT(#sql, LEN(#sql)-11);
INSERT #d EXEC sp_executesql #sql;
SELECT
db+'.'+sch+'.'+obj,
' (' + type_desc + ') references => ',
COALESCE(ref_db, db)+'.'+ref_sch+'.'+ref_obj
FROM #d;
GO
DROP TABLE #d;
GO
Sample output:
[db1].[dbo].[foo] (SQL_STORED_PROCEDURE) references => [db2].[dbo].[bar]
[db1].[dbo].[xyz] (SQL_STORED_PROCEDURE) references => [db1].[dbo].[table_xyz]
This should help you get started
create table ##tbData (
DatabaseName Varchar(64),
objectName varchar(128),
ObjectKind varchar(128)
)
go
EXEC sp_Msforeachdb "use [?];
insert ##tbData select db_name(),so.name,so.xtype from sysobjects so"
select * from ##tbdata
Essentially, build a table and the SQL statement you want to use, then use the undocumented sp_MSforEachdb to load the table from every database
You could look at something like sp_MSForeachdb and call the above query each of those databases.

Resources