Getting SQL Server Cross database Dependencies - sql

SQL Server Version - 2008 R2
I am working on evaluating a DMS solution, with an objective of taking over maintenance. The original solution has one central database, that has data pertaining to the manufacturer. It also has one database for each dealer, which means there are a lot of cross database dependencies.
The problems:
No DB documentation
No code comments
Lots of heaps
No standard object naming conventions
The central DB has 460+ tables and 900+ SProcs, in addition to other
objects
Each dealer DB has 370+ tables and 2350+ SProcs, in addition to other
objects
As a first step, I am recommending a complete clean-up of the DB, for which it is critical to understand object dependencies, including cross database dependencies. I tried using Red Gate's solution, but the output is way too voluminous. All I want is a list of objects in the databases that do not have any dependencies - they neither depend on other objects, nor are there any objects that depend on them.
Here is the script I have used to get a list of dependencies:
SELECT
DB_NAME() referencing_database_name,
OBJECT_NAME (referencing_id) referencing_entity_name,
ISNULL(referenced_schema_name,'dbo') referenced_schema_name,
referenced_entity_name,
ao.type_desc referenced_entity_type,
ISNULL(referenced_database_name,DB_NAME()) referenced_database_name
FROM sys.sql_expression_dependencies sed
JOIN sys.all_objects ao
ON sed.referenced_entity_name = ao.name
I will be creating a table - Dependencies - into which I will be inserting this result set from each DB. As a next step, I will also be creating another table - AllObjects- which will contain a list of all objects in the Databases. Here is the script to do this:
SELECT
DB_NAME() DBName,
name,
type_desc
FROM sys.all_objects
WHERE type_desc IN
(
'VIEW',
'SQL_TABLE_VALUED_FUNCTION',
'SQL_STORED_PROCEDURE',
'SQL_INLINE_TABLE_VALUED_FUNCTION',
'USER_TABLE',
'SQL_SCALAR_FUNCTION'
)
Now, a list of name from this table, that do not appear in the referenced_entity_name column in the dependencies table should give a list of objects that I am looking for.
SELECT
AO.DBName,
AO.name,
AO.type_desc
FROM AllObjects AO
LEFT OUTER JOIN Dependencies D ON
D.referenced_database_name = AO.DBName AND
D.referenced_entity_name = AO.name AND
D.referenced_entity_type = AO.type_desc
WHERE
D.referenced_database_name IS NULL AND
D.referenced_entity_name IS NULL AND
D.referenced_entity_type IS NULL
Now the questions:
Some object dependencies seem to be missing in the output. What am I
missing?
How do I validate that my findings are correct?
I mean is there a different way to do this, so I can compare the
results and double check?
Thanks in advance,
Raj

You can compare your results to the ones that the following script finds.
Here is the full article
CREATE PROCEDURE [dbo].[get_crossdatabase_dependencies] AS
SET NOCOUNT ON;
CREATE TABLE #databases(
database_id int,
database_name sysname
);
INSERT INTO #databases(database_id, database_name)
SELECT database_id, [name]
FROM sys.databases
WHERE 1 = 1
AND [state] <> 6 /* ignore offline DBs */
AND database_id > 4; /* ignore system DBs */
DECLARE
#database_id int,
#database_name sysname,
#sql varchar(max);
CREATE TABLE #dependencies(
referencing_database varchar(max),
referencing_schema varchar(max),
referencing_object_name varchar(max),
referenced_server varchar(max),
referenced_database varchar(max),
referenced_schema varchar(max),
referenced_object_name varchar(max)
);
WHILE (SELECT COUNT(*) FROM #databases) > 0 BEGIN
SELECT TOP 1 #database_id = database_id,
#database_name = database_name
FROM #databases;
SET #sql = 'INSERT INTO #dependencies select
DB_NAME(' + convert(varchar,#database_id) + '),
OBJECT_SCHEMA_NAME(referencing_id,'
+ convert(varchar,#database_id) +'),
OBJECT_NAME(referencing_id,' + convert(varchar,#database_id) + '),
referenced_server_name,
ISNULL(referenced_database_name, db_name('
+ convert(varchar,#database_id) + ')),
referenced_schema_name,
referenced_entity_name
FROM ' + quotename(#database_name) + '.sys.sql_expression_dependencies';
EXEC(#sql);
DELETE FROM #databases WHERE database_id = #database_id;
END;
SET NOCOUNT OFF;
SELECT * FROM #dependencies;

Oh, MS made a good effort at detecting cross-database dependencies with sys.sql_expression_dependencies, but I've seen it miss things before. In your case, I'd find an example of a missing dependency, and start backtracking: have you dropped it from your query some how? If so, fix your query. Does sys.sql_expression_dependencies omit a certain class of dependencies? Under what conditions? Is dynamic SQL to blame? etc.
You should also run sp_refreshsqlmodule for each object in sys.sql_modules, and then rerun your code. It forces SQL Server to refresh the dependency info (to the best of its ability).
Now, for validation, set up a trace, and listen for event 114, "Audit Schema Object Access Event", plus the starting and completed events for stored procedure and/or RPC calls. Include columns DatabaseName, ParentName, ObjectName, ServerName, SPID and RequestID (for MARS-enabled connections). Maybe some others too. "Audit Schema Object Access Event" happens anytime an object is accessed, so exercise the app while this trace is running, then collate the data using SPID + RequestId and compare it to your results using sys.sql_expression_dependencies. If anything is in the trace data that doesn't appear in your dependencies data, then you've missed something.

If you have to deal with linked servers, I adapted #MilicaMedic's answer to work for cross-server dependencies. I also output column names where available in a dependency.
You can use it like this:
create table #dependencies (
referencing_server nvarchar(128),
referencing_database nvarchar(128),
referencing_schema nvarchar(128),
referencing_object_name nvarchar(128),
referencing_column nvarchar(128),
referenced_server nvarchar(128),
referenced_database nvarchar(128),
referenced_schema nvarchar(128),
referenced_object_name nvarchar(128),
referenced_column nvarchar(128)
);
insert #dependencies
exec crossServerDependencies
'ThisServerName, LinkedServerName, LinkedServerName2, etc'
From there you join it to your AllObjects table as you described in your answer.
My code requires two external functions: "splitString", and "AddBracketsWhenNecessary". You can simplify the former and completely eliminate the latter, as you desire. But I use them for other things so they make it into my implementation. The code for both is at the bottom.
Here is the main procedure:
create procedure crossServerDependencies
#server_names_csv nvarchar(500) = null -- csv list of server names you want to pull dependencies for
as
-- Create output table
if object_id('tempdb..#dependencies') is not null
drop table #dependencies;
create table #dependencies (
referencing_server nvarchar(128),
referencing_database nvarchar(128),
referencing_schema nvarchar(128),
referencing_object_name nvarchar(128),
referencing_column nvarchar(128),
referenced_server nvarchar(128),
referenced_database nvarchar(128),
referenced_schema nvarchar(128),
referenced_object_name nvarchar(128),
referenced_column nvarchar(128)
);
-- Split server csv into table
set #server_names_csv = isnull(#server_names_csv, ##servername);
declare #server_names table (
server_row int,
server_name nvarchar(128),
actuallyExists bit
);
insert #server_names
select server_row = id,
server_name,
actuallyExists = case when sv.name is not null then 1 else 0 end
from dbo.splitString(#server_names_csv, ',') sp
cross apply (select server_name = dbo.AddBracketsWhenNecessary(val)) ap
left join sys.servers sv on sp.val = dbo.AddBracketsWhenNecessary(sv.name);
-- Loop servers
declare
#server_row int = 0,
#server_name nvarchar(50),
#server_exists bit = 0,
#server_is_local bit = 0,
#server_had_some_inserts bit = 0;
while #server_row <= (select max(server_row) from #server_names)
begin
-- Server loop initializations
set #server_row += 1;
set #server_had_some_inserts = 0;
select #server_name = server_name,
#server_exists = actuallyExists
from #server_names
where server_row = #server_row;
set #server_is_local =
case when #server_name = dbo.AddBracketsWhenNecessary(##servername) then 1 else 0 end;
-- Handle non-existent server (and prevent sql injection)
if #server_exists = 0
begin
print
'"' + #server_name + '" does not exist. ' +
'Please check your spelling and/or access to view the linked server ' +
'(running under ' + user_name() + ').';
continue;
end
-- Get database list
if object_id('tempdb..#databases') is not null
drop table #databases;
create table #databases (
rownum int identity(1,1),
database_id int,
database_name nvarchar(128)
);
declare #sql nvarchar(max) = '
select database_id, [name]
from master.sys.databases
where state <> 6 -- ignore offline dbs
and database_id > 4 -- ignore system dbs
and has_dbaccess([name]) = 1
and [name] not in (''ReportServer'', ''ReportServerTempDB'')
';
if #server_is_local = 0
begin
set #sql = replace(#sql, '''', '''''');
set #sql = 'select * from openquery( #server_name, ''' + #sql + ''')';
end
set #sql = 'insert #databases (database_id, database_name)' + #sql;
set #sql = replace(#sql, '#server_name', #server_name);
exec (#sql);
delete #databases
where database_name = 'ReportServer';
-- Loop databases
declare #rowNum int = 0;
while #rowNum <= (select max(rownum) from #databases)
begin
-- Database loop initializations
set #rowNum += 1;
declare
#database_id nvarchar(max),
#database_name nvarchar(max);
select #database_id = database_id,
#database_name = dbo.AddBracketsWhenNecessary(database_name)
from #databases
where rownum = #rowNum;
-- Get object dependency info
set #sql = '
with
getTableColumnIds as (
select table_id = o.object_id,
table_name = o.name,
column_id = c.column_id,
column_name = c.name
from #database_name.sys.objects o
join #database_name.sys.all_columns c on o.object_id = c.object_id
)
#insertStatement
select ''#server_name'',
db_name(#database_id),
object_schema_name(referencing_id, #database_id),
object_name(referencing_id, #database_id),
referencing_column = ringTCs.column_name,
isnull(referenced_server_name, ''#server_name''),
isnull(referenced_database_name, db_name(#database_id)),
isnull(referenced_schema_name, ''dbo''),
referenced_entity_name,
referenced_column = redTCs.column_name
from #database_name.sys.sql_expression_dependencies d
left join getTableColumnIds ringTCs
on d.referencing_id = ringTCs.table_id
and d.referencing_minor_id = ringTCs.column_id
left join getTableColumnIds redTCs
on d.referenced_id = redTCs.table_id
and d.referenced_minor_id = redTCs.column_id
';
set #sql = replace(#sql, '#database_id', #database_id);
set #sql = replace(#sql, '#database_name', #database_name);
if #server_is_local = 0
begin
set #sql = replace(#sql, '''', '''''');
set #sql = replace(#sql, '#insertStatement', '');
set #sql = 'select * from openquery(#server_name, ''' + #sql + ''')';
end
set #sql = replace(#sql, '#insertStatement', 'insert #dependencies ');
set #sql = replace(#sql, '#server_name', #server_name);
exec (#sql);
-- Database loop terminations
if ##rowcount > 0
set #server_had_some_inserts = 1;
end -- database loop
-- server loop terminations
if #server_had_some_inserts = 0
begin
declare #remote_user_name nvarchar(255);
select #remote_user_name = remote_name
from sys.linked_logins li
join sys.servers s on li.server_id = s.server_id
where remote_name is not null
and s.name = 'sisag'
print (
'No dependencies found for ' + #server_name + '. ' +
'If this is unexpected, you may need to run "grant view any definition to ' +
'[' + isnull(#remote_user_name, '?') + ']" ' +
'on the remote server.'
);
end
end -- server loop
-- Terminate
select * from #dependencies
The code for AddBracketsWhenNecessary:
create function AddBracketsWhenNecessary (
#objectName nvarchar(250)
)
returns nvarchar(250) as
begin
if left(#objectName, 1) = '[' and right(#objectName, 1) = ']'
return #objectName;
declare #hasInvalidCharacter bit;
select #hasInvalidCharacter = max(isInvalid)
from dbo.splitString(#objectName, null) chars
cross apply (select
isLetter = patindex('[a-z,_]', val),
isNumber = PATINDEX('[0-9]', val)
) getCharType
cross apply (select
isInvalid =
case
when isLetter = 1 then 0
when isNumber = 1 and not chars.id = 1 then 0
else 1
end
) getValidity
return
case when #hasInvalidCharacter = 1 then '[' else '' end
+ #objectName
+ case when #hasInvalidCharacter = 1 then ']' else '' end;
end
Any finally, my splitter function (but see Arnold Fribble here if you want a simpler version, or use the built in function if you have SqlServer 2016 or above):
create function splitString (
#stringToSplit nvarchar(max),
#delimiter nvarchar(50)
)
returns table as
return
with
split_by_delimiter as (
select id = 1,
start = 1,
stop = convert(int,
charindex(#delimiter, #stringToSplit)
)
union all
select id = id + 1,
start = newStart,
stop = convert(int,
charindex(#delimiter, #stringToSplit, newStart)
)
from split_by_delimiter
cross apply (select newStart = stop + len(#delimiter)) ap
where Stop > 0
),
split_into_characters as (
select id = 1,
chr = left(#stringToSplit,1)
union all
select id = id + 1,
chr = substring(#stringToSplit, ID + 1, 1)
from split_into_characters
where id < len(#stringToSplit)
)
select id,
val =
ltrim(rtrim(substring(
#stringToSplit,
start,
case
when stop > 0 then stop - start
else len(#stringtosplit)
end
)))
from split_by_delimiter
where len(#delimiter) > 0
union all
select id,
val = chr
from split_into_characters
where #delimiter = ''
or #delimiter is null
I had to make some small changes from the real code I use, so if there are any reference errors, please let me know in the comments and I'll edit.

A Query I often use to find the tables used from other databases is the following:
SELECT OBJECT_NAME (referencing_id) AS referencing_object, referenced_database_name,
referenced_schema_name, referenced_entity_name
FROM sys.sql_expression_dependencies
WHERE referenced_database_name IS NOT NULL
AND is_ambiguous = 0;
This gives you all tables used in the stored procedures / views that origin from this database, but also other databases.
source

I upgraded one of the answer adding referencing/referenced id and referencing/referenced type like table, view, etc.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[get_crossdatabase_dependencies] AS
SET NOCOUNT ON;
CREATE TABLE #databases(
database_id int,
database_name sysname
);
INSERT INTO #databases(database_id, database_name)
SELECT database_id, [name]
FROM sys.databases
WHERE 1 = 1
AND [state] <> 6 /* ignore offline DBs */
AND database_id NOT IN (4, 5, 6, 7, 11, 13, 14); /* ignore system DBs */
DECLARE
#database_id int,
#database_name sysname,
#sql varchar(max);
CREATE TABLE #dependencies(
referencing_id int,
referencing_database varchar(max),
referencing_schema varchar(max),
referencing_object_name varchar(max),
referencing_type varchar(max),
referenced_id int,
referenced_server varchar(max),
referenced_database varchar(max),
referenced_schema varchar(max),
referenced_object_name varchar(max),
referenced_type varchar(max),
);
WHILE (SELECT COUNT(*) FROM #databases) > 0 BEGIN
SELECT TOP 1 #database_id = database_id,
#database_name = database_name
FROM #databases;
SET #sql = 'INSERT INTO #dependencies select
referencing_id,
DB_NAME(' + convert(varchar,#database_id) + '),
OBJECT_SCHEMA_NAME(referencing_id,'
+ convert(varchar,#database_id) +'),
OBJECT_NAME(referencing_id,' + convert(varchar,#database_id) + '),
CASE
WHEN OBJECTPROPERTY(referencing_id, ''IsTable'') = 1 THEN ''Table''
WHEN OBJECTPROPERTY(referencing_id, ''IsView'') = 1 THEN ''View''
WHEN OBJECTPROPERTY(referencing_id, ''IsProcedure'') = 1 THEN ''Procedure''
WHEN OBJECTPROPERTY(referencing_id, ''IsTableFunction'') = 1 THEN ''Table-valued Function''
ELSE ''Unknown''
END AS referencing_type,
referenced_id,
referenced_server_name,
ISNULL(referenced_database_name, db_name('
+ convert(varchar,#database_id) + ')),
referenced_schema_name,
referenced_entity_name,
CASE
WHEN OBJECTPROPERTY(referenced_id, ''IsTable'') = 1 THEN ''Table''
WHEN OBJECTPROPERTY(referenced_id, ''IsView'') = 1 THEN ''View''
WHEN OBJECTPROPERTY(referenced_id, ''IsProcedure'') = 1 THEN ''Procedure''
WHEN OBJECTPROPERTY(referenced_id, ''IsTableFunction'') = 1 THEN ''Table-valued Function''
ELSE ''Unknown''
END AS referenced_type
FROM ' + quotename(#database_name) + '.sys.sql_expression_dependencies
ORDER BY
referencing_type';
EXEC(#sql);
DELETE FROM #databases WHERE database_id = #database_id;
END;
SET NOCOUNT OFF;
SELECT * FROM #dependencies;

Related

Search for a particular string in an entire database [duplicate]

I know it's possible, but I don't know how.
I need to search an SQL Server database for all mentions of a specific string.
For example: I would like to search all tables, views, functions, stored procedures, ... for string "tblEmployes" (not data within the tables).
One of the reasons I need this is I would like to remove some extra data tables that are created, but I am afraid that they are maybe used somewhere in procedures or functions.
This will search every column of every table in a specific database. Create the stored procedure on the database that you want to search in.
The Ten Most Asked SQL Server Questions And Their Answers:
CREATE PROCEDURE FindMyData_String
#DataToFind NVARCHAR(4000),
#ExactMatch BIT = 0
AS
SET NOCOUNT ON
DECLARE #Temp TABLE(RowId INT IDENTITY(1,1), SchemaName sysname, TableName sysname, ColumnName SysName, DataType VARCHAR(100), DataFound BIT)
INSERT INTO #Temp(TableName,SchemaName, ColumnName, DataType)
SELECT C.Table_Name,C.TABLE_SCHEMA, C.Column_Name, C.Data_Type
FROM Information_Schema.Columns AS C
INNER Join Information_Schema.Tables AS T
ON C.Table_Name = T.Table_Name
AND C.TABLE_SCHEMA = T.TABLE_SCHEMA
WHERE Table_Type = 'Base Table'
And Data_Type In ('ntext','text','nvarchar','nchar','varchar','char')
DECLARE #i INT
DECLARE #MAX INT
DECLARE #TableName sysname
DECLARE #ColumnName sysname
DECLARE #SchemaName sysname
DECLARE #SQL NVARCHAR(4000)
DECLARE #PARAMETERS NVARCHAR(4000)
DECLARE #DataExists BIT
DECLARE #SQLTemplate NVARCHAR(4000)
SELECT #SQLTemplate = CASE WHEN #ExactMatch = 1
THEN 'If Exists(Select *
From ReplaceTableName
Where Convert(nVarChar(4000), [ReplaceColumnName])
= ''' + #DataToFind + '''
)
Set #DataExists = 1
Else
Set #DataExists = 0'
ELSE 'If Exists(Select *
From ReplaceTableName
Where Convert(nVarChar(4000), [ReplaceColumnName])
Like ''%' + #DataToFind + '%''
)
Set #DataExists = 1
Else
Set #DataExists = 0'
END,
#PARAMETERS = '#DataExists Bit OUTPUT',
#i = 1
SELECT #i = 1, #MAX = MAX(RowId)
FROM #Temp
WHILE #i <= #MAX
BEGIN
SELECT #SQL = REPLACE(REPLACE(#SQLTemplate, 'ReplaceTableName', QUOTENAME(SchemaName) + '.' + QUOTENAME(TableName)), 'ReplaceColumnName', ColumnName)
FROM #Temp
WHERE RowId = #i
PRINT #SQL
EXEC SP_EXECUTESQL #SQL, #PARAMETERS, #DataExists = #DataExists OUTPUT
IF #DataExists =1
UPDATE #Temp SET DataFound = 1 WHERE RowId = #i
SET #i = #i + 1
END
SELECT SchemaName,TableName, ColumnName
FROM #Temp
WHERE DataFound = 1
GO
To run it, just do this:
exec FindMyData_string 'google', 0
It works amazingly well!!!
If you need to find database objects (e.g. tables, columns, and triggers) by name - have a look at the free Redgate Software tool called SQL Search which does this - it searches your entire database for any kind of string(s).
It's a great must-have tool for any DBA or database developer - did I already mention it's absolutely free to use for any kind of use??
You can also try ApexSQL Search – it’s a free SSMS add-in similar to SQL Search.
If you really want to use only SQL you might want to try this script:
select
S.name as [Schema],
o.name as [Object],
o.type_desc as [Object_Type],
C.text as [Object_Definition]
from sys.all_objects O inner join sys.schemas S on O.schema_id = S.schema_id
inner join sys.syscomments C on O.object_id = C.id
where S.schema_id not in (3,4) -- avoid searching in sys and INFORMATION_SCHEMA schemas
and C.text like '%ICE_%'
order by [Schema]
You can export your database (if small) to your hard drive / desktop, and then just do a string search via a text search program or text editor.
For getting a table by name in SQL Server:
SELECT *
FROM sys.Tables
WHERE name LIKE '%Employees%'
For finding a stored procedure by name:
SELECT name
FROM sys.objects
WHERE name = 'spName'
To get all stored procedures related to a table:
----Option 1
SELECT DISTINCT so.name
FROM syscomments sc
INNER JOIN sysobjects so ON sc.id=so.id
WHERE sc.TEXT LIKE '%tablename%'
----Option 2
SELECT DISTINCT o.name, o.xtype
FROM syscomments c
INNER JOIN sysobjects o ON c.id=o.id
WHERE c.TEXT LIKE '%tablename%'
This code searching procedure and function but not search in table :)
SELECT name
FROM sys.all_objects
WHERE Object_definition(object_id)
LIKE '%text%'
ORDER BY name
You could;
Script the database to a single file and search the file for tblEmployees using a text editor. In SQL Server Management Studio (SSMS), right click over the database and choose Generate Scripts.
Use SSMS 'View Dependencies' by right clicking over tblEmployees to see which other objects are dependent on it
Use a free third-party tool such as Redgate Software's SQL Search to search all database objects by name and content by keyword.
My version...
I named it "Needle in the haystack" for obvious reasons.
It searches for a specific value in each row and each column, not for column names, etc.
Execute search (replace values for the first two variables of course):
DECLARE #SEARCH_DB VARCHAR(100)='REPLACE_WITH_YOUR_DB_NAME'
DECLARE #SEARCH_VALUE_LIKE NVARCHAR(100)=N'%REPLACE_WITH_SEARCH_STRING%'
SET NOCOUNT ON;
DECLARE col_cur CURSOR FOR
SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE
FROM information_schema.columns WHERE TABLE_CATALOG=#SEARCH_DB AND DATA_TYPE NOT IN ('timestamp', 'datetime');
DECLARE #TOTAL int = (SELECT COUNT(*)
FROM information_schema.columns WHERE TABLE_CATALOG=#SEARCH_DB AND DATA_TYPE NOT IN ('timestamp', 'datetime'));
DECLARE #TABLE_CATALOG nvarchar(500), #TABLE_SCHEMA nvarchar(500), #TABLE_NAME nvarchar(500), #COLUMN_NAME nvarchar(500), #DATA_TYPE nvarchar(500);
DECLARE #SQL nvarchar(4000)='';
PRINT '-------- BEGIN SEARCH --------';
OPEN col_cur;
FETCH NEXT FROM col_cur INTO #TABLE_CATALOG, #TABLE_SCHEMA, #TABLE_NAME, #COLUMN_NAME, #DATA_TYPE;
BEGIN TRY DROP TABLE ##RESULTS; END TRY BEGIN CATCH END CATCH
CREATE TABLE ##RESULTS( TABLE_CATALOG nvarchar(500), TABLE_SCHEMA nvarchar(500), TABLE_NAME nvarchar(500), COLUMN_NAME nvarchar(500), DATA_TYPE nvarchar(500), RECORDS int)
DECLARE #SHOULD_CAST bit=0
DECLARE #i int =0
DECLARE #progress_sum bigint=0
WHILE ##FETCH_STATUS = 0
BEGIN
-- PRINT '' + CAST(#i as varchar(100)) +' of ' + CAST(#TOTAL as varchar(100)) + ' ' + #TABLE_CATALOG+'.'+#TABLE_SCHEMA+'.'+#TABLE_NAME+': '+#COLUMN_NAME+' ('+#DATA_TYPE+')';
SET #SHOULD_CAST = (SELECT CASE #DATA_TYPE
WHEN 'varchar' THEN 0
WHEN 'nvarchar' THEN 0
WHEN 'char' THEN 0
ELSE 1 END)
SET #SQL='SELECT '''+#TABLE_CATALOG+''' catalog_name, '''+#TABLE_SCHEMA+''' schema_name, '''+#TABLE_NAME+''' table_name, '''+#COLUMN_NAME+''' column_name, '''+#DATA_TYPE+''' data_type, ' +
+' COUNT(['+#COLUMN_NAME+']) records '+
+' FROM '+#TABLE_CATALOG+'.'+#TABLE_SCHEMA+'.'+#TABLE_NAME +
+' WHERE ' + CASE WHEN #SHOULD_CAST=1 THEN 'CAST(['+#COLUMN_NAME + '] as NVARCHAR(max)) ' ELSE ' ['+#COLUMN_NAME + '] ' END
+' LIKE '''+ #SEARCH_VALUE_LIKE + ''' '
-- PRINT #SQL;
IF #i % 100 = 0
BEGIN
SET #progress_sum = (SELECT SUM(RECORDS) FROM ##RESULTS)
PRINT CAST (#i as varchar(100)) +' of ' + CAST(#TOTAL as varchar(100)) +': '+ CAST (#progress_sum as varchar(100))
END
INSERT INTO ##RESULTS (TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE, RECORDS)
EXEC(#SQL)
FETCH NEXT FROM col_cur INTO #TABLE_CATALOG, #TABLE_SCHEMA, #TABLE_NAME, #COLUMN_NAME, #DATA_TYPE;
SET #i=#i+1
-- IF #i > 1000
-- BREAK
END
CLOSE col_cur;
DEALLOCATE col_cur;
SELECT * FROM ##RESULTS WHERE RECORDS>0;
Then to view results, even while executing, from another window, execute:
DECLARE #SEARCH_VALUE_LIKE NVARCHAR(100)=N'%#FLEX#%'
SELECT * FROM ##RESULTS WHERE RECORDS>0;
SET NOCOUNT ON;
DECLARE col_cur CURSOR FOR
SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE
FROM ##RESULTS WHERE RECORDS>0;
DECLARE #TABLE_CATALOG nvarchar(500), #TABLE_SCHEMA nvarchar(500), #TABLE_NAME nvarchar(500), #COLUMN_NAME nvarchar(500), #DATA_TYPE nvarchar(500);
DECLARE #SQL nvarchar(4000)='';
OPEN col_cur;
FETCH NEXT FROM col_cur INTO #TABLE_CATALOG, #TABLE_SCHEMA, #TABLE_NAME, #COLUMN_NAME, #DATA_TYPE;
DECLARE #i int =0
DECLARE #SHOULD_CAST bit=0
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SHOULD_CAST = (SELECT CASE #DATA_TYPE
WHEN 'varchar' THEN 0
WHEN 'nvarchar' THEN 0
WHEN 'char' THEN 0
ELSE 1 END)
SET #SQL='SELECT '''+#TABLE_CATALOG+''' catalog_name, '''+#TABLE_SCHEMA+''' schema_name, '''+#TABLE_NAME+''' table_name, '''+#COLUMN_NAME+''' column_name, '''+#DATA_TYPE+''' data_type, ' +
+' ['+#COLUMN_NAME+']'+
+', * '
+' FROM '+#TABLE_CATALOG+'.'+#TABLE_SCHEMA+'.'+#TABLE_NAME +
+' WHERE ' + CASE WHEN #SHOULD_CAST=1 THEN 'CAST(['+#COLUMN_NAME + '] as NVARCHAR(max)) ' ELSE ' ['+#COLUMN_NAME + '] ' END
+' LIKE '''+ #SEARCH_VALUE_LIKE + ''' '
PRINT #SQL;
EXEC(#SQL)
FETCH NEXT FROM col_cur INTO #TABLE_CATALOG, #TABLE_SCHEMA, #TABLE_NAME, #COLUMN_NAME, #DATA_TYPE;
SET #i=#i+1
-- IF #i > 10
-- BREAK
END
CLOSE col_cur;
DEALLOCATE col_cur;
Few mentions about it:
it uses cursors instead of a blocking while loop
it can print progress (uncomment if needed)
it can exit after a few attempts (uncomment the IF at the end)
it displays all records
you can fine tune it as needed
DISCLAIMERS:
DO NOT run it in production environments!
It is slow. If the DB is accessed by other services/users, please add " WITH (NOLOCK) " after every table name in all the selects, especially the dynamic select ones.
It does not validate/protect against all sorts of SQL injection options.
If your DB is huge, prepare yourself for some sleep, make sure the query will not be killed after a few minutes.
It casts some values to string, including ints/bigints/smallints/tinyints. If you don't need those, put them at the same exclusion lists with the timestamps at the top of the script.
The content of all stored procedures, views and functions are stored in field text of table sysComments. The name of all objects are stored in table sysObjects and the columns are in sysColumns.
Having this information, you can use this code to search in content of views, stored procedures, and functions for the specified word:
Select b.name from syscomments a
inner join sysobjects b on a.id = b.id
where text like '%tblEmployes%'
This query will give you the objects which contains the word "tblEmployes" .
To search by the name of Objects you can use this code:
Select name from sysobjects
where name like '%tblEmployes%'
And finally to find the objects having at least one column containing the word "tblEmployes", you can use this code:
Select b.name from syscolumns a inner join sysobjects b on a.id = b.id
where a.name like '%tblEmployes%'
You can combine these three queries with union:
Select distinct b.name from syscomments a
inner join sysobjects b on a.id = b.id
where text like '%tblEmployes%'
union
Select distinct name from sysobjects
where name like '%tblEmployes%'
union
Select distinct b.name from syscolumns a inner join sysobjects b on a.id = b.id
where a.name like '%tblEmployes%'
With this query you have all objects containing the word "tblEmployes" in content or name or as a column.
I was given access to a database, but not the table where my query was being stored in.
Inspired by #marc_s answer, I had a look at HeidiSQL which is a Windows program that can deal with MySQL, SQL Server, and PostgreSQL.
I found that it can also search a database for a string.
It will search each table and give you how many times it found the string per table!
This will search for a string over every database:
declare #search_term varchar(max)
set #search_term = 'something'
select #search_term = 'use ? SET QUOTED_IDENTIFIER ON
select
''[''+db_name()+''].[''+c.name+''].[''+b.name+'']'' as [object],
b.type_desc as [type],
d.obj_def.value(''.'',''varchar(max)'') as [definition]
from (
select distinct
a.id
from sys.syscomments a
where a.[text] like ''%'+#search_term+'%''
) a
inner join sys.all_objects b
on b.[object_id] = a.id
inner join sys.schemas c
on c.[schema_id] = b.[schema_id]
cross apply (
select
[text()] = a1.[text]
from sys.syscomments a1
where a1.id = a.id
order by a1.colid
for xml path(''''), type
) d(obj_def)
where c.schema_id not in (3,4) -- avoid searching in sys and INFORMATION_SCHEMA schemas
and db_id() not in (1,2,3,4) -- avoid sys databases'
if object_id('tempdb..#textsearch') is not null drop table #textsearch
create table #textsearch
(
[object] varchar(300),
[type] varchar(300),
[definition] varchar(max)
)
insert #textsearch
exec sp_MSforeachdb #search_term
select *
from #textsearch
order by [object]
If I want to find where anything I want to search is, I use this:
DECLARE #search_string varchar(200)
SET #search_string = '%myString%'
SELECT DISTINCT
o.name AS Object_Name,
o.type_desc,
m.definition
FROM sys.sql_modules m
INNER JOIN
sys.objects o
ON m.object_id = o.object_id
WHERE m.definition Like #search_string;
It's easy to search a string in your database with phpmyadmin. There you can chose from many search options and you can see where your search phrase is mentioned.
Here is the same script as submitted by user l--''''''---------'''''''''''', but corrected to work on a case-sensitive SQL instance, and with some other minor improvements.
DROP PROCEDURE IF EXISTS dbo.spFind_Text_In_Database
GO
CREATE PROCEDURE dbo.spFind_Text_In_Database
#strText_To_Find NVARCHAR(4000),
#bitExact_Match BIT = 0
AS
SET NOCOUNT ON
DECLARE #Temp TABLE(RowId INT IDENTITY(1,1), SchemaName sysname, TableName sysname, ColumnName SysName, DataType VARCHAR(100), DataFound BIT)
INSERT INTO #Temp(TableName,SchemaName, ColumnName, DataType)
SELECT C.TABLE_NAME, C.TABLE_SCHEMA, C.COLUMN_NAME, C.DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS AS C
INNER Join INFORMATION_SCHEMA.TABLES AS T
ON C.TABLE_NAME = T.TABLE_NAME
AND C.TABLE_SCHEMA = T.TABLE_SCHEMA
WHERE TABLE_TYPE = 'BASE TABLE'
And DATA_TYPE In ('ntext','text','nvarchar','nchar','varchar','char')
DECLARE #i INT
DECLARE #MAX INT
DECLARE #TableName sysname
DECLARE #ColumnName sysname
DECLARE #SchemaName sysname
DECLARE #SQL NVARCHAR(4000)
DECLARE #PARAMETERS NVARCHAR(4000)
DECLARE #DataExists BIT
DECLARE #SQLTemplate NVARCHAR(4000)
SELECT #SQLTemplate = CASE WHEN #bitExact_Match = 1
THEN 'If Exists(Select *
From ReplaceTableName
Where Convert(nVarChar(4000), [ReplaceColumnName])
= ''' + #strText_To_Find + '''
)
Set #DataExists = 1
Else
Set #DataExists = 0'
ELSE 'If Exists(Select *
From ReplaceTableName
Where Convert(nVarChar(4000), [ReplaceColumnName])
Like ''%' + #strText_To_Find + '%''
)
Set #DataExists = 1
Else
Set #DataExists = 0'
END,
#PARAMETERS = '#DataExists Bit OUTPUT',
#i = 1
SELECT #i = 1, #MAX = MAX(RowId)
FROM #Temp
WHILE #i <= #MAX
BEGIN
SELECT #SQL = REPLACE(REPLACE(#SQLTemplate, 'ReplaceTableName', QUOTENAME(SchemaName) + '.' + QUOTENAME(TableName)), 'ReplaceColumnName', ColumnName)
FROM #Temp
WHERE RowId = #i
PRINT #SQL
EXEC sp_executesql #SQL, #PARAMETERS, #DataExists = #DataExists OUTPUT
IF #DataExists =1
UPDATE #Temp SET DataFound = 1 WHERE RowId = #i
SET #i = #i + 1
END
SELECT SchemaName,TableName, ColumnName
FROM #Temp
WHERE DataFound = 1
GO
Searching SQL Database objects is possible with SQL Server Management Studio (SSMS) with the following methods, with SSMS Object Search: object explorer details or T-SQL scripts as explained in following:
Different ways to search for SQL Server database objects
SQL Server Find Anything in Object Explorer in SSMS
Search text with wildcards
Here is how you can search the database in Swift using the FMDB library.
First, go to this link and add this to your project: FMDB. When you have done that, then here is how you do it. For example, you have a table called Person, and you have firstName and secondName and you want to find data by first name, here is a code for that:
func loadDataByfirstName(firstName : String, completion: #escaping CompletionHandler){
if isDatabaseOpened {
let query = "select * from Person where firstName like '\(firstName)'"
do {
let results = try database.executeQuery(query, values: [firstName])
while results.next() {
let firstName = results.string(forColumn: "firstName") ?? ""
let lastName = results.string(forColumn: "lastName") ?? ""
let newPerson = Person(firstName: firstName, lastName: lastName)
self.persons.append(newPerson)
}
completion(true)
}catch let err {
completion(false)
print(err.localizedDescription)
}
database.close()
}
}
Then in your ViewController you will write this to find the person detail you are looking for:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
SQLManager.instance.openDatabase { (success) in
if success {
SQLManager.instance.loadDataByfirstName(firstName: "Hardi") { (success) in
if success {
// You have your data Here
}
}
}
}
}

Select all databases that have a certain table and a certain column

I need to create a query that is executed on all databases of my SQL server instance. An additional constraint is, that the query should only be executed on databases that contain a special table with a special column. Background is that in some databases the special table does (not) have the special column.
Based on this solution, what I have until now is a query that executes only on databases that contain a certain table.
SELECT *
FROM sys.databases
WHERE DATABASEPROPERTY(name, 'IsSingleUser') = 0
AND HAS_DBACCESS(name) = 1
AND state_desc = 'ONLINE'
AND CASE WHEN state_desc = 'ONLINE'
THEN OBJECT_ID(QUOTENAME(name) + '.[dbo].[CERTAIN_TABLE]', 'U')
END IS NOT NULL
However, what is still missing is a constraint that the query should only select databases where the table CERTAIN_TABLE has a specific column. How can this be achieved?
When i want to loop through all databases, i do a loop like the following. Its easy to follow:
DECLARE #dbs TABLE ( dbName NVARCHAR(100) )
DECLARE #results TABLE ( resultName NVARCHAR(100) )
INSERT INTO #dbs
SELECT name FROM sys.databases
DECLARE #current NVARCHAR(100)
WHILE (SELECT COUNT(*) FROM #dbs) > 0
BEGIN
SET #current = (SELECT TOP 1 dbName FROM #dbs)
INSERT INTO #results
EXEC
(
'IF EXISTS(SELECT 1 FROM "' + #current + '".INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = ''Target_Table_Name'' AND COLUMN_NAME = ''Target_Column_Name'')
BEGIN
--table and column exists, execute query here
SELECT ''' + #current + '''
END'
)
DELETE FROM #dbs
WHERE dbName = #current
END
SELECT * FROM #results
You are going to need either some looping or dynamic sql for this. I really dislike loops so here is how you could do this with dynamic sql.
declare #TableName sysname = 'CERTAIN_TABLE'
, #ColumnName sysname = 'CERTAIN_COLUMN'
declare #SQL nvarchar(max) = ''
select #SQL = #SQL + 'select DatabaseName = ''' + db.name + ''' from ' + QUOTENAME(db.name) + '.sys.tables t join ' + QUOTENAME(db.name) + '.sys.columns c on c.object_id = t.object_id where t.name = ''' + QUOTENAME(#TableName) + ''' and c.name = ''' + QUOTENAME(#ColumnName) + '''' + char(10) + 'UNION ALL '
from sys.databases db
where db.state_desc = 'ONLINE'
order by db.name
select #SQL = substring(#SQL, 0, len(#SQL) - 9)
select #SQL
--uncomment the line below when you are comfortable the query generated is correct
--exec sp_executesql #SQL

How can I return a distinct count of a variable for all tables in my database?

I have a SQL database with 60+ tables, almost all of which are populated with a CLIENTID field. I want to count the number of unique client IDs in each table.
The results I'm looking for are:
TABLE_NAME; CLIENTID_COUNT
dbo.HISTORY; 650
dbo.VISITS; 596
dbo.SALES; 1053
...; ...
This seems like it should be so simple but I've been playing around with cursors for hours and can't figure this one out. Please help!
IF OBJECT_ID('tempdb..#temp_RESULTS') IS NOT NULL DROP TABLE #temp_RESULTS
CREATE TABLE #TEMP_RESULTS
(
TABLENAME VARCHAR(MAX),
CLIENTCNT BIGINT
)
DECLARE #TABLENAME VARCHAR(MAX)
DECLARE #command VARCHAR(MAX)
IF OBJECT_ID('tempdb..#temp_PROCESS') IS NOT NULL DROP TABLE #temp_PROCESS
SELECT * INTO #TEMP_PROCESS FROM sys.tables
WHILE EXISTS(SELECT * FROM [#TEMP_PROCESS])
BEGIN
SET #TABLENAME = (SELECT TOP 1 [NAME] FROM [#TEMP_PROCESS])
SET #command = ('SELECT ''' + #TABLENAME + ''', COUNT(DISTINCT CLIENTID) AS CLIENTCNT FROM ' + #TABLENAME)
SELECT #command
INSERT INTO #TEMP_RESULTS
EXEC(#command)
DELETE FROM [#TEMP_PROCESS] WHERE [NAME] = #TABLENAME
END
SELECT * FROM [#TEMP_RESULTS]
Assuming the column is exactly ClientId in every table, you should be able to use this as is:
DROP TABLE IF EXISTS #clientId
CREATE TABLE #clientId
(
TableName nvarchar(1000),
ClientIdCount bigint
)
DECLARE #TableName nvarchar(1000);
DECLARE #CurrentQuery nvarchar(2000);
DECLARE result_cursor CURSOR local fast_forward FOR
SELECT DISTINCT
'['+TABLE_SCHEMA + '].[' + TABLE_NAME + ']'
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
COLUMN_NAME = 'ClientId'
OPEN result_cursor
FETCH NEXT FROM result_cursor into #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #CurrentQuery = 'SELECT ''' + #TableName + ''', COUNT(DISTINCT ClientId) FROM ' + #TableName
--print #CurrentQuery
INSERT INTO
#clientId
(
TableName,
ClientIdCount
)
EXEC(#CurrentQuery)
FETCH NEXT FROM result_cursor into #TableName
END
--end loop
--clean up
CLOSE result_cursor
DEALLOCATE result_cursor
GO
SELECT
*
FROM
#clientId
You could use dynamic sql.
This will read through your system tables, find those that have a ClientID column, and build the text of a query that's in the general shape of 'Select Count(DISTINCT ClientID)' from each table.
DECLARE #SQLQuery as nvarchar(max) = ''
------------------------------------
-- GET THE TABLES THAT HAVE A CLIENTID FROM SCHEMA
SELECT #SQLQuery = #SQLQuery + qryTxt FROM (
SELECT DISTINCT 'SELECT ''' + tables.name + ''', COUNT(DISTINCT CLIENTID) FROM ' + tables.name + ' UNION ' AS qryTxt
FROM sys.columns left join sys.tables on columns.object_id = tables.object_id where columns.name = CLIENTID AND isnull(tables.name, '') <> '') subquery
------------------------------------
-- REMOVE THE LAST 'UNION' KEYWORD FROM SQLQUERY
SET #SQLQuery = left(#sqlQuery, len(#sqlQuery) - 5)
------------------------------------
-- EXECUTE
execute sp_executesql #SQLQuery
I really dislike cursors and loops. Even though this is not going to be much difference for a performance perspective I like to share how you can leverage the system tables and dynamic sql to avoid using a cursor, while loop or temp tables for something like this.
This code is literally all you need to to do this.
declare #SQL nvarchar(max) = ''
select #SQL = #SQL + 'select TableName = ''' + t.name + ''', ClientID_Count = count(distinct clientID)
from ' + QUOTENAME(t.name) + ' UNION ALL '
from sys.tables t
join sys.columns c on c.object_id = t.object_id
where c.name = 'clientID'
select #SQL = left(#SQL, len(#SQL) - 10) --removes the last UNION ALL
select #SQL
--once your comfortable the dynamic sql is correct just uncomment the line below.
--exec sp_executesql #SQL
A similar pattern to other answers here, but this is how I would tackle it:
IF OBJECT_ID('#Tables', 'U') IS NOT NULL
DROP TABLE #Tables;
SELECT ID = IDENTITY(INT, 1, 1),
SchemaName = OBJECT_SCHEMA_NAME([object_id]),
TableName = OBJECT_NAME([object_id]),
ColumnName = name,
DistinctCount = 0
INTO #Tables
FROM sys.columns
WHERE name = 'CLIENTID';
DECLARE #ID INT = 1,
#MaxID INT = (SELECT MAX(ID) FROM #Tables);
WHILE #ID < #MaxID
BEGIN;
DECLARE #SQLCommand VARCHAR(MAX);
SELECT #SQLCommand = FORMATMESSAGE('
UPDATE #Tables SET DistinctCount = (
SELECT COUNT(DISTINCT %s) FROM %s.%s
)
WHERE ID = %i;',
QUOTENAME(ColumnName), QUOTENAME(SchemaName), QUOTENAME(TableName), ID)
FROM #Tables
WHERE ID = #ID;
EXEC (#SQLCommand);
SET #ID += 1;
END;
SELECT *
FROM #Tables;

How to Generate Scripts For All Triggers in Database Using Microsoft SQL Server Management Studio

I'd like to generate an SQL Script that contains the SQL to create all of the triggers that exist in our database. The triggers were added directly via the SSMS query pane so, there is currently no source other than the trigger on the database itself.
I have already tried the method where you right-click the database, select Tasks->Generate Scripts and used the "Script Entire Database and All Objects" option. While this does create a SQL script for the tables and constraints, it does not generate SQL for the triggers.
I also understand that I can right click on each trigger in the database and select the Generate SQL Script option but, there is currently 46 tables under audit (For Insert, Update, and Delete).
Rather manually generate an insert, update, and delete trigger script for each of the 46 tables, is there an easier way to do this? Or, should I start clicking, copying, and pasting?
Database-> Tasks-> Generate Scripts -> Next -> Next
On Choose Script Options UI, under Table/View Options Heading, set Script Triggers to True.
I know the answer has been accepted already, but want to provide another solution for cases when for some reason SSMS wizard is not able to generate script for triggers (in my case it was MSSQL2008R2)
This solution is based on idea from dana above, but uses 'sql_modules' instead to provide the full code of the trigger if it exceeds 4000 chars (restriction of 'text' column of 'syscomments' view)
select [definition],'GO' from sys.sql_modules m
inner join sys.objects obj on obj.object_id=m.object_id
where obj.type ='TR'
Right click on the results grid and then "Save results as..." saves to file with formatting preserved
How about this?
select text from syscomments where text like '%CREATE TRIGGER%'
EDIT - per jj's comment below, syscomments is deprecated and will be removed in the future. Please use either the wizard-based or script-based solutions listed above moving forward :)
To script all triggers you can define the stored procedure:
SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
-- Procedure:
-- [dbo].[SYS_ScriptAllTriggers]
--
-- Parameter:
-- #ScriptMode bit
-- possible values:
-- 0 - Script ALTER only
-- 1 - Script CREATE only
-- 2 - Script DROP + CREATE
ALTER PROCEDURE [dbo].[SYS_ScriptAllTriggers]
#ScriptMode int = 0
AS
BEGIN
DECLARE #script TABLE (script varchar(max), id int identity (1,1))
DECLARE
#SQL VARCHAR(8000),
#Text NVARCHAR(4000),
#BlankSpaceAdded INT,
#BasePos INT,
#CurrentPos INT,
#TextLength INT,
#LineId INT,
#MaxID INT,
#AddOnLen INT,
#LFCR INT,
#DefinedLength INT,
#SyscomText NVARCHAR(4000),
#Line NVARCHAR(1000),
#UserName SYSNAME,
#ObjID INT,
#OldTrigID INT;
SET NOCOUNT ON;
SET #DefinedLength = 1000;
SET #BlankSpaceAdded = 0;
SET #ScriptMode = ISNULL(#ScriptMode, 0);
-- This Part Validated the Input parameters
DECLARE #Triggers TABLE (username SYSNAME NOT NULL, trigname SYSNAME NOT NULL, objid INT NOT NULL);
DECLARE #TrigText TABLE (objid INT NOT NULL, lineid INT NOT NULL, linetext NVARCHAR(1000) NULL);
INSERT INTO
#Triggers (username, trigname, objid)
SELECT DISTINCT
OBJECT_SCHEMA_NAME(B.id), B.name, B.id
FROM
dbo.sysobjects B, dbo.syscomments C
WHERE
B.type = 'TR' AND B.id = C.id AND C.encrypted = 0;
IF EXISTS(SELECT C.* FROM syscomments C, sysobjects O WHERE O.id = C.id AND O.type = 'TR' AND C.encrypted = 1)
BEGIN
insert into #script select '/*';
insert into #script select 'The following encrypted triggers were found';
insert into #script select 'The procedure could not write the script for it';
insert into
#script
SELECT DISTINCT
'[' + OBJECT_SCHEMA_NAME(B.id) + '].[' + B.name + ']' --, B.id
FROM
dbo.sysobjects B, dbo.syscomments C
WHERE
B.type = 'TR' AND B.id = C.id AND C.encrypted = 1;
insert into #script select '*/';
END;
DECLARE ms_crs_syscom CURSOR LOCAL forward_only FOR
SELECT
T.objid, C.text
FROM
#Triggers T, dbo.syscomments C
WHERE
T.objid = C.id
ORDER BY T.objid,
C.colid
FOR READ ONLY;
SELECT #LFCR = 2;
SELECT #LineId = 1;
OPEN ms_crs_syscom;
SET #OldTrigID = -1;
FETCH NEXT FROM ms_crs_syscom INTO #ObjID, #SyscomText;
WHILE ##fetch_status = 0
BEGIN
SELECT #BasePos = 1;
SELECT #CurrentPos = 1;
SELECT #TextLength = LEN(#SyscomText);
IF #ObjID <> #OldTrigID
BEGIN
SET #LineID = 1;
SET #OldTrigID = #ObjID;
END;
WHILE #CurrentPos != 0
BEGIN
--Looking for end of line followed by carriage return
SELECT #CurrentPos = CHARINDEX(CHAR(13) + CHAR(10), #SyscomText, #BasePos);
--If carriage return found
IF #CurrentPos != 0
BEGIN
WHILE ( ISNULL(LEN(#Line), 0) + #BlankSpaceAdded + #CurrentPos - #BasePos + #LFCR ) > #DefinedLength
BEGIN
SELECT #AddOnLen = #DefinedLength - (ISNULL(LEN(#Line), 0) + #BlankSpaceAdded );
INSERT
#TrigText
VALUES
( #ObjID, #LineId, ISNULL(#Line, N'') + ISNULL(SUBSTRING(#SyscomText, #BasePos, #AddOnLen), N''));
SELECT
#Line = NULL,
#LineId = #LineId + 1,
#BasePos = #BasePos + #AddOnLen,
#BlankSpaceAdded = 0;
END;
SELECT #Line = ISNULL(#Line, N'') + ISNULL(SUBSTRING(#SyscomText, #BasePos, #CurrentPos - #BasePos + #LFCR), N'');
SELECT #BasePos = #CurrentPos + 2;
INSERT
#TrigText
VALUES
( #ObjID, #LineId, #Line );
SELECT #LineId = #LineId + 1;
SELECT #Line = NULL;
END;
ELSE
--else carriage return not found
BEGIN
IF #BasePos <= #TextLength
BEGIN
/*If new value for #Lines length will be > then the
**defined length
*/
WHILE ( ISNULL(LEN(#Line), 0) + #BlankSpaceAdded + #TextLength - #BasePos + 1 ) > #DefinedLength
BEGIN
SELECT #AddOnLen = #DefinedLength - ( ISNULL(LEN(#Line), 0 ) + #BlankSpaceAdded );
INSERT
#TrigText
VALUES
( #ObjID, #LineId, ISNULL(#Line, N'') + ISNULL(SUBSTRING(#SyscomText, #BasePos, #AddOnLen), N''));
SELECT
#Line = NULL,
#LineId = #LineId + 1,
#BasePos = #BasePos + #AddOnLen,
#BlankSpaceAdded = 0;
END;
SELECT #Line = ISNULL(#Line, N'') + ISNULL(SUBSTRING(#SyscomText, #BasePos, #TextLength - #BasePos+1 ), N'');
IF LEN(#Line) < #DefinedLength AND CHARINDEX(' ', #SyscomText, #TextLength + 1) > 0
BEGIN
SELECT
#Line = #Line + ' ',
#BlankSpaceAdded = 1;
END;
END;
END;
END;
FETCH NEXT FROM ms_crs_syscom INTO #ObjID, #SyscomText;
END;
IF #Line IS NOT NULL
INSERT
#TrigText
VALUES
( #ObjID, #LineId, #Line );
CLOSE ms_crs_syscom;
insert into #script select '-- You should run this result under dbo if your triggers belong to multiple users';
insert into #script select '';
IF #ScriptMode = 2
BEGIN
insert into #script select '-- Dropping the Triggers';
insert into #script select '';
insert into #script
SELECT
'IF EXISTS(SELECT * FROM sysobjects WHERE id = OBJECT_ID(''[' + username + '].[' + trigname + ']'')'
+ ' AND ObjectProperty(OBJECT_ID(''[' + username + '].[' + trigname + ']''), ''ISTRIGGER'') = 1)'
+ ' DROP TRIGGER [' + username + '].[' + trigname +']' + CHAR(13) + CHAR(10)
+ 'GO' + CHAR(13) + CHAR(10)
FROM
#Triggers;
END;
IF #ScriptMode = 0
BEGIN
update
#TrigText
set
linetext = replace(linetext, 'CREATE TRIGGER', 'ALTER TRIGGER')
WHERE
upper(left(replace(ltrim(linetext), char(9), ''), 14)) = 'CREATE TRIGGER'
END
insert into #script select '----------------------------------------------';
insert into #script select '-- Creation of Triggers';
insert into #script select '';
insert into #script select '';
DECLARE ms_users CURSOR LOCAL forward_only FOR
SELECT
T.username,
T.objid,
MAX(D.lineid)
FROM
#Triggers T,
#TrigText D
WHERE
T.objid = D.objid
GROUP BY
T.username,
T.objid
FOR READ ONLY;
OPEN ms_users;
FETCH NEXT FROM ms_users INTO #UserName, #ObjID, #MaxID;
WHILE ##fetch_status = 0
BEGIN
insert into #script select 'setuser N''' + #UserName + '''' + CHAR(13) + CHAR(10);
insert into #script
SELECT
'-- Text of the Trigger' =
CASE lineid
WHEN 1 THEN 'GO' + CHAR(13) + CHAR(10) + linetext
WHEN #MaxID THEN linetext + 'GO'
ELSE linetext
END
FROM
#TrigText
WHERE
objid = #ObjID
ORDER
BY lineid;
insert into #script select 'setuser';
FETCH NEXT FROM ms_users INTO #UserName, #ObjID, #MaxID;
END;
CLOSE ms_users;
insert into #script select 'GO';
insert into #script select '------End ------';
DEALLOCATE ms_crs_syscom;
DEALLOCATE ms_users;
select script from #script order by id
END
How to execute it:
SET nocount ON
DECLARE #return_value INT
EXEC #return_value = [dbo].[SYS_ScriptAllTriggers] #InclDrop = 1
SELECT 'Return Value' = #return_value
GO
Using my own version with the combination of answer found in here and other post(can't find the original quetion.
select OBJECT_NAME(parent_obj) AS table_name,sysobj.name AS trigger_name,
[definition],'GO'
from sys.sql_modules m
inner join sysobjects sysobj on sysobj.id=m.object_id
INNER JOIN sys.tables t ON sysobj.parent_obj = t.object_id
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE sysobj.type = 'TR' and sysobj.name like 'NAME_OF_TRIGGER'
order by sysobj.name

SQL Server find first gap between ID key fields

Is there any other better way to perform this operation?
-- USE EXAMPLE: EXEC GetFirstIdInGap #tableName ='Employees',#column='IdEmployee'
CREATE PROCEDURE GetFirstIdInGap
(#tableName sysname,
#column sysname)
AS
IF #tableName IS NOT NULL and #column IS NOT NULL
BEGIN
DECLARE #col varchar(50), #col2 varchar(50)
SET #col = 'A.' + #column;
SET #col2 = 'A2.' + #column;
EXEC ('SELECT ISNULL((MIN('+#col+') - 1),(SELECT ISNULL(MAX('+#column+')+1,1) FROM '+#tableName+'))
AS '+#column+'
FROM '+#tableName+' AS a
LEFT JOIN '+#tableName+' AS a2
ON '+#col2+' = '+#col+' - 1
WHERE '+#col2+' IS NULL AND '+#col+' > 1');
END
GO
It gets the first free ID (if there are gaps) or the last one + 1 given a #tableName and #column. If there are no rows, it returns as the first ID = 1.
UPDATE:
For those who have asked about why do I need gaps of ID's, I am gonna explain my problem (although I didn't want to dig into it). I work with C# Winforms applications against other firmware applications which have serious memory restrictions. One of those restrictions is that I can only use a maximum code value of 65536. Those codes are equivalent of database ID's, and in some cases the firmware code had reached the value of 65536. That's why gap reusing would be wonderful for me.
t is your table
select
coalesce((select min(id)+1 from t mt where not exists(select 1 from t where id+1 = mt.id )), 1) firstgap
Here is an approach that doesn't require a numbers table (even one with more than 1,000 rows):
CREATE PROCEDURE dbo.GetFirstIdInGap_2
#table SYSNAME,
#column SYSNAME
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX) = N';WITH c AS
(
SELECT n = ' + #column + ',
rn = ROW_NUMBER() OVER (ORDER BY ' + #column + ')
FROM ' + #table + '
)
SELECT ' + #column + ' = 1 + COALESCE(
(SELECT MIN(c.n) FROM c INNER JOIN c AS n
ON n.rn = c.rn + 1 WHERE n.n - c.n > 1),
(SELECT MAX(c.n) FROM c),
0);';
EXEC sp_executesql #sql;
END
GO
t is your table
select min(isnull(id,0)+1) from t where isnull(id,0) + 1 not in (select isnull(id,0) from t)