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)