I have this query in a SP:
select #QUERY =
COALESCE(#QUERY+' UNION ALL ','') +
'SELECT ''' +
c.name + ''' AS [ID], CAST([' + c.name + '] AS VarChar(MAX)) as [Value],''' +
t.name + ''' AS [Type] FROM ' + #dynDb + '.dbo.' +
#TableName +
' WHERE actorId = '+ CAST(#ActorId as nvarchar(max)) +
' and languageId = ''' + CAST(#LanguageId AS NVARCHAR(max))+ ''''
FROM cmssystemprocess.dbo.syscolumns c
INNER JOIN cmssystemprocess.dbo.SYSTYPES T ON T.XTYPE = C.XTYPE AND T.NAME != 'SYSNAME'
INNER JOIN cmssystemprocess.dbo.sysobjects o on c.id = o.id and o.xtype = 'u'
WHERE
o.name = #TableName and
(c.name like 'C%' or c.name like 'id') and
c.name not like 'created%'
ORDER BY c.colid
I want to get the name of database here in a variable (lets say #dyndb) and put it in the query instead of cmssystemprocess.dbo..
The only way to parameterize the database you're querying is with dynamic SQL, which means your proc will have to create dynamic SQL within dynamic SQL. That can get ugly very quickly.
Some tips:
use sp_executesql and pass in all of your variables (#dynDb, #ActorId, etc), as well as #QUERY as an output variable, via the #params parameter.
construct the dynamic SQL string using backticks (`) rather than doubling up on the single quotes. Then, once the string is built, replace(#QUERY,'`','''').
when building dynamic SQL within dynamic SQL, use a different single characters in place of single quotes in each "level" of the SQL.
Using the SQL query in your question, I would
Change all instances of doubled-up single quotes to a single backtick, for readability.
Wrap the select statement with replace(...,'`','''') to restore the doubled-up quotes
Take the result of that and replace all single quotes with another seldom-used-but-reminiscent-of-a-quote character such as ^
replace the instances of cmssystemprocess with a placeholder such as #DB#
Wrap the entire thing with two replace() functions to embed the DB name and change all the ^ back to doubled-up single quotes
Here's a mock-up:
-- Mimic stored proc parms
declare #QUERY nvarchar(max)
,#SpDbParam nvarchar(128) = 'cmssystemprocess'
,#dynDb nvarchar(128)
,#ActorId nvarchar(max)
,#LanguageId nvarchar(max)
,#TableName nvarchar(128)
; -- end stored proc parms mockup
-- Actual code for your proc follows
declare #CMD nvarchar(max)
,#Params nvarchar(max) = '
#dynDb nvarchar(128)
,#ActorId nvarchar(max)
,#LanguageId nvarchar(max)
,#TableName nvarchar(128)
,#QUERY nvarchar(max) output';
set #CMD = replace(replace('
select #QUERY = replace(
COALESCE(#QUERY+^ UNION ALL ^,^^) +
^SELECT `^ +
c.name + ^` AS [ID], CAST([^ + c.name + ^] AS VarChar(MAX)) as [Value],`^ +
t.name + ^` AS [Type] FROM ^ + #dynDb + ^.dbo.^ +
#TableName +
^ WHERE actorId = ^+ CAST(#ActorId as nvarchar(max)) +
^ and languageId = `^ + CAST(#LanguageId AS NVARCHAR(max))+ ^`^
,^`^,^^^^)
FROM #DB#.dbo.syscolumns c
INNER JOIN #DB#.dbo.SYSTYPES T ON T.XTYPE = C.XTYPE AND T.NAME != ^SYSNAME^
INNER JOIN #DB#.dbo.sysobjects o on c.id = o.id and o.xtype = ^u^
WHERE
o.name = #TableName and
(c.name like ^C%^ or c.name like ^id^) and
c.name not like ^created%^
ORDER BY c.colid'
,'#DB#',quotename(#SpDbParam))
,'^' ,'''');
print #CMD; -- for debugging / showing output in this stackoverflow post
exec sp_executesql #CMD, #Params, #dynDb, #ActorId, #LanguageId, #TableName, #QUERY output;
select #QUERY = replace(
COALESCE(#QUERY+' UNION ALL ','') +
'SELECT `' +
c.name + '` AS [ID], CAST([' + c.name + '] AS VarChar(MAX)) as [Value],`' +
t.name + '` AS [Type] FROM ' + #dynDb + '.dbo.' +
#TableName +
' WHERE actorId = '+ CAST(#ActorId as nvarchar(max)) +
' and languageId = `' + CAST(#LanguageId AS NVARCHAR(max))+ '`'
,'`','''')
FROM [cmssystemprocess].dbo.syscolumns c
INNER JOIN [cmssystemprocess].dbo.SYSTYPES T ON T.XTYPE = C.XTYPE AND T.NAME != 'SYSNAME'
INNER JOIN [cmssystemprocess].dbo.sysobjects o on c.id = o.id and o.xtype = 'u'
WHERE
o.name = #TableName and
(c.name like 'C%' or c.name like 'id') and
c.name not like 'created%'
ORDER BY c.colid
Related
I want to replace a single character in each column of every table of the database; however, I don't want to do it table-by-table.
Is there a way to do the whole thing in one attempt?
Assuming only text values will be modified, you can do something like below.
IF(NOT EXISTS (SELECT * FROM sys.tables where name = 'TEMPQUERYTABLE' and type_desc = 'USER_TABLE'))
BEGIN
SELECT T.name AS Table_Name ,
C.name AS Column_Name ,
P.name AS Data_Type ,
P.max_length AS Size ,
CAST(P.precision AS VARCHAR) + '/' + CAST(P.scale AS VARCHAR) AS Precision_Scale
INTO TEMPQUERYTABLE
FROM sys.objects AS T
JOIN sys.columns AS C ON T.object_id = C.object_id
JOIN sys.types AS P ON C.system_type_id = P.system_type_id
WHERE T.type_desc = 'USER_TABLE' AND P.name in ('nvarchar','varchar') AND T.name <> 'TEMPQUERYTABLE'
END
DECLARE #SQL NVARCHAR(MAX)
DECLARE #Old_value VARCHAR(10)
DECLARE #New_value VARCHAR(10)
SET #Old_value = 'xx'
SET #New_value = 'yy'
SET #SQL = ''
SELECT #SQL = #SQL + 'UPDATE ' + Table_Name + ' SET ' + Column_Name + ' = REPLACE(' + Column_Name + ',' + #Old_value +','+ #New_value + ')' + CHAR(13) + CHAR(10)
FROM TEMPQUERYTABLE
EXEC(#SQL)
--DROP TABLE TEMPQUERYTABLE
But I'm curious to know why you need such thing done in the first place.
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)
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);
I am using the following SQL to list all table and column names in my schema for tables containing columns whose names contain the string "code" using the following SQL server query:
SELECT
a.table_name, a.column_name from (SELECT t.name AS table_name,
SCHEMA_NAME(schema_id) AS schema_name,
c.name AS column_name
FROM
sys.tables AS t
INNER JOIN
sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
WHERE
c.name LIKE '%code%') a
Result:
Table Name Column Name
---------- -----------
Tab_1_name a_code
Tab_2_name another_code
Tab_3_name yet_another_code
and so on...
I would like to now query the actual data in the a_code and another_code columns using a wrapper but cannot see how to get at the actual data (if doing for Tab 1 individually for example, I would
SELECT a_code FROM Tab_1
to get
a_code
------
value 1
value 2
value 3
but can't figure out or find anywhere how to code the outer query to wrap around the above such that I would get something along the lines of:
Tab1_name a_code
--------- ------
tab_name 1 value 1
tab_name 1 value 2
tab_name 2 value 1
tab_name 2 value 2
tab_name 3 value 1
tab_name 3 value 2 ... etc.
i.e. a formatted list of all the data values in all table columns in my schema/DB whose names contain the word "code"?
Without dynamic SQL, this can't be done by anyway.
Here is something to get you started.
DECLARE #SearchTerm NVARCHAR(50)
SELECT #SearchTerm = '%id%'
SELECT t.name AS table_name,
SCHEMA_NAME(schema_id) AS schema_name,
c.name AS column_name
INTO #temp
FROM sys.tables AS t
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
WHERE c.name LIKE #SearchTerm
ORDER BY t.name
DECLARE #Query NVARCHAR(MAX),
#tableName NVARCHAR(250),
#schemaName NVARCHAR(10),
#columnName NVARCHAR(250)
SELECT #Query = 'SELECT SchemaName = '''',
TableName = '''',
ColumnName = '''',
Value = CONVERT(NVARCHAR(MAX), '''')
WHERE 0 = 1'
WHILE(EXISTS(SELECT TOP 1 1 FROM #temp))
BEGIN
SELECT TOP 1 #tableName = table_name,
#schemaName = [schema_name],
#columnName = column_name
FROM #temp
SELECT #Query = #Query + ' UNION ALL SELECT SchemaName = ''' + #schemaName + ''',
TableName = ''' + #tableName + ''',
ColumnName = ''' + #columnName + ''',
Value = CASE WHEN ' + #columnName + ' IS NULL THEN ''NULL'' ELSE CONVERT(NVARCHAR(MAX), ' + #columnName + ') END
FROM ' + #tableName
DELETE #temp
WHERE table_name = #tableName
AND #schemaName = [schema_name]
AND #columnName = column_name
END
PRINT #Query
EXEC sp_executesql #Query
DROP TABLE #temp
The above query return the following information :
SchemaName TableName ColumnName Value
Beaware that by returning the value for all matching columns, you are very likely to encounter conversion problem and null conversion problem. In the query above, basic case are handled, but the conversion to 'NVARCHAR' might still fail with some complexes SQL column type.
use master
GO
declare
#sql varchar(max) = '',
#colpattern varchar(100) = '%name%'
;with cteSchema as
(
select
object_schema_name(t.object_id) + '.' + quotename(t.name) as tabname,
quotename(c.name) as colname
from sys.tables t
inner join sys.columns c on c.object_id = t.object_id
where c.name like #colpattern
)
select #sql =
(
select
cast('
select cast(t.' as varchar(max)) + t.colname + ' as varchar(1000)) as [value] '
+ ', cast(''' + t.tabname + '.' + t.colname + ''' as nvarchar(2000)) as [source] '
+ ' from ' + t.tabname + ' t
union all '
from cteSchema t
order by t.tabname, t.colname
for xml path(''), type
).value('.', 'varchar(max)')
+ '
select null, null where 1=0
order by [source], [value]'
print #sql
exec (#sql)
GO
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.