How to list row count of each table in the database. Some equivalent of
select count(*) from table1
select count(*) from table2
...
select count(*) from tableN
I will post a solution but other approaches are welcome
If you're using SQL Server 2005 and up, you can also use this:
SELECT
t.NAME AS TableName,
i.name as indexName,
p.[Rows],
sum(a.total_pages) as TotalPages,
sum(a.used_pages) as UsedPages,
sum(a.data_pages) as DataPages,
(sum(a.total_pages) * 8) / 1024 as TotalSpaceMB,
(sum(a.used_pages) * 8) / 1024 as UsedSpaceMB,
(sum(a.data_pages) * 8) / 1024 as DataSpaceMB
FROM
sys.tables t
INNER JOIN
sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN
sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN
sys.allocation_units a ON p.partition_id = a.container_id
WHERE
t.NAME NOT LIKE 'dt%' AND
i.OBJECT_ID > 255 AND
i.index_id <= 1
GROUP BY
t.NAME, i.object_id, i.index_id, i.name, p.[Rows]
ORDER BY
object_name(i.object_id)
In my opinion, it's easier to handle than the sp_msforeachtable output.
A snippet I found at http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=21021 that helped me:
select t.name TableName, i.rows Records
from sysobjects t, sysindexes i
where t.xtype = 'U' and i.id = t.id and i.indid in (0,1)
order by TableName;
To get that information in SQL Management Studio, right click on the database, then select Reports --> Standard Reports --> Disk Usage by Table.
SELECT
T.NAME AS 'TABLE NAME',
P.[ROWS] AS 'NO OF ROWS'
FROM SYS.TABLES T
INNER JOIN SYS.PARTITIONS P ON T.OBJECT_ID=P.OBJECT_ID;
As seen here, this will return correct counts, where methods using the meta data tables will only return estimates.
CREATE PROCEDURE ListTableRowCounts
AS
BEGIN
SET NOCOUNT ON
CREATE TABLE #TableCounts
(
TableName VARCHAR(500),
CountOf INT
)
INSERT #TableCounts
EXEC sp_msForEachTable
'SELECT PARSENAME(''?'', 1),
COUNT(*) FROM ? WITH (NOLOCK)'
SELECT TableName , CountOf
FROM #TableCounts
ORDER BY TableName
DROP TABLE #TableCounts
END
GO
sp_MSForEachTable 'DECLARE #t AS VARCHAR(MAX);
SELECT #t = CAST(COUNT(1) as VARCHAR(MAX))
+ CHAR(9) + CHAR(9) + ''?'' FROM ? ; PRINT #t'
Output:
Well luckily SQL Server management studio gives you a hint on how to do this.
Do this,
start a SQL Server trace and open the activity you are doing (filter
by your login ID if you're not alone and set the application Name
to Microsoft SQL Server Management Studio), pause the trace and discard any results you have recorded till now;
Then, right click a table and select property from the pop up menu;
start the trace again;
Now in SQL Server Management studio select the storage property item on the left;
Pause the trace and have a look at what TSQL is generated by microsoft.
In the probably last query you will see a statement starting with exec sp_executesql N'SELECT
when you copy the executed code to visual studio you will notice that this code generates all the data the engineers at microsoft used to populate the property window.
when you make moderate modifications to that query you will get to something like this:
SELECT
SCHEMA_NAME(tbl.schema_id)+'.'+tbl.name as [table], --> something I added
p.partition_number AS [PartitionNumber],
prv.value AS [RightBoundaryValue],
fg.name AS [FileGroupName],
CAST(pf.boundary_value_on_right AS int) AS [RangeType],
CAST(p.rows AS float) AS [RowCount],
p.data_compression AS [DataCompression]
FROM sys.tables AS tbl
INNER JOIN sys.indexes AS idx ON idx.object_id = tbl.object_id and idx.index_id < 2
INNER JOIN sys.partitions AS p ON p.object_id=CAST(tbl.object_id AS int) AND p.index_id=idx.index_id
LEFT OUTER JOIN sys.destination_data_spaces AS dds ON dds.partition_scheme_id = idx.data_space_id and dds.destination_id = p.partition_number
LEFT OUTER JOIN sys.partition_schemes AS ps ON ps.data_space_id = idx.data_space_id
LEFT OUTER JOIN sys.partition_range_values AS prv ON prv.boundary_id = p.partition_number and prv.function_id = ps.function_id
LEFT OUTER JOIN sys.filegroups AS fg ON fg.data_space_id = dds.data_space_id or fg.data_space_id = idx.data_space_id
LEFT OUTER JOIN sys.partition_functions AS pf ON pf.function_id = prv.function_id
Now the query is not perfect and you could update it to meet other questions you might have, the point is, you can use the knowledge of microsoft to get to most of the questions you have by executing the data you're interested in and trace the TSQL generated using profiler.
I kind of like to think that MS engineers know how SQL server work and, it will generate TSQL that works on all items you can work with using the version on SSMS you are using so it's quite good on a large variety releases prerviouse, current and future.
And remember, don't just copy, try to understand it as well else you might end up with the wrong solution.
Walter
This approaches uses string concatenation to produce a statement with all tables and their counts dynamically, like the example(s) given in the original question:
SELECT COUNT(*) AS Count,'[dbo].[tbl1]' AS TableName FROM [dbo].[tbl1]
UNION ALL SELECT COUNT(*) AS Count,'[dbo].[tbl2]' AS TableName FROM [dbo].[tbl2]
UNION ALL SELECT...
Finally this is executed with EXEC:
DECLARE #cmd VARCHAR(MAX)=STUFF(
(
SELECT 'UNION ALL SELECT COUNT(*) AS Count,'''
+ QUOTENAME(t.TABLE_SCHEMA) + '.' + QUOTENAME(t.TABLE_NAME)
+ ''' AS TableName FROM ' + QUOTENAME(t.TABLE_SCHEMA) + '.' + QUOTENAME(t.TABLE_NAME)
FROM INFORMATION_SCHEMA.TABLES AS t
WHERE TABLE_TYPE='BASE TABLE'
FOR XML PATH('')
),1,10,'');
EXEC(#cmd);
The first thing that came to mind was to use sp_msForEachTable
exec sp_msforeachtable 'select count(*) from ?'
that does not list the table names though, so it can be extended to
exec sp_msforeachtable 'select parsename(''?'', 1), count(*) from ?'
The problem here is that if the database has more than 100 tables you will get the following error message:
The query has exceeded the maximum
number of result sets that can be
displayed in the results grid. Only
the first 100 result sets are
displayed in the grid.
So I ended up using table variable to store the results
declare #stats table (n sysname, c int)
insert into #stats
exec sp_msforeachtable 'select parsename(''?'', 1), count(*) from ?'
select
*
from #stats
order by c desc
Fastest way to find row count of all tables in SQL Refreence (http://www.codeproject.com/Tips/811017/Fastest-way-to-find-row-count-of-all-tables-in-SQL)
SELECT T.name AS [TABLE NAME], I.rows AS [ROWCOUNT]
FROM sys.tables AS T
INNER JOIN sys.sysindexes AS I ON T.object_id = I.id
AND I.indid < 2
ORDER BY I.rows DESC
I want to share what's working for me
SELECT
QUOTENAME(SCHEMA_NAME(sOBJ.schema_id)) + '.' + QUOTENAME(sOBJ.name) AS [TableName]
, SUM(sdmvPTNS.row_count) AS [RowCount]
FROM
sys.objects AS sOBJ
INNER JOIN sys.dm_db_partition_stats AS sdmvPTNS
ON sOBJ.object_id = sdmvPTNS.object_id
WHERE
sOBJ.type = 'U'
AND sOBJ.is_ms_shipped = 0x0
AND sdmvPTNS.index_id < 2
GROUP BY
sOBJ.schema_id
, sOBJ.name
ORDER BY [TableName]
GO
The database is hosted in Azure and the final result is:
Credit: https://www.mssqltips.com/sqlservertip/2537/sql-server-row-count-for-all-tables-in-a-database/
Here is my take on this question. It contains all schemas and lists only tables with rows. YMMV
select distinct schema_name(t.schema_id) as schema_name, t.name as
table_name, p.[Rows]
from sys.tables as t
INNER JOIN sys.indexes as i ON t.OBJECT_ID = i.object_id
INNER JOIN sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id =
p.index_id
where p.[Rows] > 0
order by schema_name;
If you use MySQL >4.x you can use this:
select TABLE_NAME, TABLE_ROWS from information_schema.TABLES where TABLE_SCHEMA="test";
Keep in mind that for some storage engines, TABLE_ROWS is an approximation.
The accepted answer didn't work for me on Azure SQL, here's one that did, it's super fast and did exactly what I wanted:
select t.name, s.row_count
from sys.tables t
join sys.dm_db_partition_stats s
ON t.object_id = s.object_id
and t.type_desc = 'USER_TABLE'
and t.name not like '%dss%'
and s.index_id = 1
order by s.row_count desc
You could try this:
SELECT OBJECT_SCHEMA_NAME(ps.object_Id) AS [schemaname],
OBJECT_NAME(ps.object_id) AS [tablename],
row_count AS [rows]
FROM sys.dm_db_partition_stats ps
WHERE OBJECT_SCHEMA_NAME(ps.object_Id) <> 'sys' AND ps.index_id < 2
ORDER BY
OBJECT_SCHEMA_NAME(ps.object_Id),
OBJECT_NAME(ps.object_id)
This sql script gives the schema, table name and row count of each table in a database selected:
SELECT SCHEMA_NAME(schema_id) AS [SchemaName],
[Tables].name AS [TableName],
SUM([Partitions].[rows]) AS [TotalRowCount]
FROM sys.tables AS [Tables]
JOIN sys.partitions AS [Partitions]
ON [Tables].[object_id] = [Partitions].[object_id]
AND [Partitions].index_id IN ( 0, 1 )
-- WHERE [Tables].name = N'name of the table'
GROUP BY SCHEMA_NAME(schema_id), [Tables].name
order by [TotalRowCount] desc
Ref: https://blog.sqlauthority.com/2017/05/24/sql-server-find-row-count-every-table-database-efficiently/
Another way of doing this:
SELECT o.NAME TABLENAME,
i.rowcnt
FROM sysindexes AS i
INNER JOIN sysobjects AS o ON i.id = o.id
WHERE i.indid < 2 AND OBJECTPROPERTY(o.id, 'IsMSShipped') = 0
ORDER BY i.rowcnt desc
I think that the shortest, fastest and simplest way would be:
SELECT
object_name(object_id) AS [Table],
SUM(row_count) AS [Count]
FROM
sys.dm_db_partition_stats
WHERE
--object_schema_name(object_id) = 'dbo' AND
index_id < 2
GROUP BY
object_id
USE DatabaseName
CREATE TABLE #counts
(
table_name varchar(255),
row_count int
)
EXEC sp_MSForEachTable #command1='INSERT #counts (table_name, row_count) SELECT ''?'', COUNT(*) FROM ?'
SELECT table_name, row_count FROM #counts ORDER BY table_name, row_count DESC
DROP TABLE #counts
From this question:
https://dba.stackexchange.com/questions/114958/list-all-tables-from-all-user-databases/230411#230411
I added record count to the answer provided by #Aaron Bertrand that lists all databases and all tables.
DECLARE #src NVARCHAR(MAX), #sql NVARCHAR(MAX);
SELECT #sql = N'', #src = N' UNION ALL
SELECT ''$d'' as ''database'',
s.name COLLATE SQL_Latin1_General_CP1_CI_AI as ''schema'',
t.name COLLATE SQL_Latin1_General_CP1_CI_AI as ''table'' ,
ind.rows as record_count
FROM [$d].sys.schemas AS s
INNER JOIN [$d].sys.tables AS t ON s.[schema_id] = t.[schema_id]
INNER JOIN [$d].sys.sysindexes AS ind ON t.[object_id] = ind.[id]
where ind.indid < 2';
SELECT #sql = #sql + REPLACE(#src, '$d', name)
FROM sys.databases
WHERE database_id > 4
AND [state] = 0
AND HAS_DBACCESS(name) = 1;
SET #sql = STUFF(#sql, 1, 10, CHAR(13) + CHAR(10));
PRINT #sql;
--EXEC sys.sp_executesql #sql;
You can copy, past and execute this piece of code to get all table record counts into a table. Note: Code is commented with instructions
create procedure RowCountsPro
as
begin
--drop the table if exist on each exicution
IF OBJECT_ID (N'dbo.RowCounts', N'U') IS NOT NULL
DROP TABLE dbo.RowCounts;
-- creating new table
CREATE TABLE RowCounts
( [TableName] VARCHAR(150)
, [RowCount] INT
, [Reserved] NVARCHAR(50)
, [Data] NVARCHAR(50)
, [Index_Size] NVARCHAR(50)
, [UnUsed] NVARCHAR(50))
--inserting all records
INSERT INTO RowCounts([TableName], [RowCount],[Reserved],[Data],[Index_Size],[UnUsed])
-- "sp_MSforeachtable" System Procedure, 'sp_spaceused "?"' param to get records and resources used
EXEC sp_MSforeachtable 'sp_spaceused "?"'
-- selecting data and returning a table of data
SELECT [TableName], [RowCount],[Reserved],[Data],[Index_Size],[UnUsed]
FROM RowCounts
ORDER BY [TableName]
end
I have tested this code and it works fine on SQL Server 2014.
SELECT ( Schema_name(A.schema_id) + '.' + A.NAME ) AS TableName,
Sum(B.rows)AS RecordCount
FROM sys.objects A INNER JOIN sys.partitions B
ON A.object_id = B.object_id WHERE A.type = 'U'
GROUP BY A.schema_id,A.NAME ;
QUERY_PHOTO
QUERY_RESULT_PHOTO
Shnugo's answer is the ONLY one that works in Azure with Externa Tables. (1) Azure SQL doesn't support sp_MSforeachtable at all and (2) rows in sys.partitions for an External table is always 0.
select T.object_id, T.name, I.indid, I.rows
from Sys.tables T
left join Sys.sysindexes I
on (I.id = T.object_id and (indid =1 or indid =0 ))
where T.type='U'
Here indid=1 means a CLUSTERED index and indid=0 is a HEAP
i have declared a variable #S and i am storing a sub query value in it which is returning more than one record , now what i want is to use it in a select statement , can i do that is it possible,
here is my query what i was trying but getting an error Must declare the scalar variable "#S"
Declare #S AS NVarchar(MAX)
SET #S = '(SELECT es.FirstName FROM [User] es WHERE es.UserId IN (SELECT CustomerUserID FROM OrderInfo))'
SELECT
OrderInfoId,
BorrowerFirstName As ConsumerFirstName,
BorrowerLastName As ConsumerLastName,
RequestedURL,
Requests,
SELECT #S,
u.FirstName +'' ''+ u.LastName As Affiliate,
o.RequestDateTime As DateOfTransaction,
o.RequestIPAddress As OriginatingIPAddress,
o.Requests As Status
from orderInfo o
inner join [User] u on o.AffiliateId = u.UserId
is it possible to do that. any help will be appreciated
If you want to append as a single string the result of the sub-query to every row produced by the main query, then, first of all you have to initialize #S:
Declare #S AS NVarchar(MAX) = ''
then properly set it:
SELECT #S = #S + ' ' + es.FirstName
FROM [User] es
WHERE es.UserId IN (SELECT CustomerUserID FROM OrderInfo)
and finally consume its contents in the main query:
SELECT
OrderInfoId,
BorrowerFirstName As ConsumerFirstName,
BorrowerLastName As ConsumerLastName,
RequestedURL,
Requests,
(SELECT #S),
u.FirstName +'' ''+ u.LastName As Affiliate,
o.RequestDateTime As DateOfTransaction,
o.RequestIPAddress As OriginatingIPAddress,
o.Requests As Status
from orderInfo o
inner join [User] u on o.AffiliateId = u.UserId
Your biggest issue is that you're trying to select multiple rows into a single column. This can't be done. You will need to concatenate the FirstNames into a single value. There are a few ways to do this. One popular way is to use STUFF with FOR XML This is an example of how you would get all of the FirstNames that match your sub query into a column. The names will be comma separated.
SELECT
OrderInfoId,
BorrowerFirstName AS ConsumerFirstName,
BorrowerLastName AS ConsumerLastName,
RequestedURL,
Requests,
STUFF((SELECT
', ' + es.FirstName
FROM
[User] es
WHERE
es.UserId IN (SELECT
CustomerUserID
FROM
OrderInfo)
ORDER BY
es.FirstName
FOR
XML PATH('')
),1,2,'') AS CustomerFirstNames,
u.FirstName + ' ' + u.LastName AS Affiliate,
o.RequestDateTime AS DateOfTransaction,
o.RequestIPAddress AS OriginatingIPAddress,
o.Requests AS Status
FROM
orderInfo o
INNER JOIN [User] u ON o.AffiliateId = u.UserId
This seems a little strange too considering you're going to get ALL user first names that have a CustomerID in orderInfo. You might want to filter your sub query by orderInfo.Id or something.
Are you sure you're not just trying to get the CustomerID first name? You can join to [User] again to get this information.
SELECT
OrderInfoId,
BorrowerFirstName AS ConsumerFirstName,
BorrowerLastName AS ConsumerLastName,
RequestedURL,
Requests,
cu.FirstName AS Customer,
u.FirstName + ' ' + u.LastName AS Affiliate,
o.RequestDateTime AS DateOfTransaction,
o.RequestIPAddress AS OriginatingIPAddress,
o.Requests AS Status
FROM
orderInfo o
INNER JOIN [User] u ON o.AffiliateId = u.UserId
INNER JOIN [User] cu ON o.CustomerUserID = cu.UserId
you need to make the entire sql statement a string, and use sp_executesql like so:
DECLARE #OrderID int;
SET #ParmDefinition = N'#SubQuery varchar(255), '+
'#OrderInfoOUT varchar(30) OUTPUT';
SET #S = '(SELECT es.FirstName FROM [User] es WHERE es.UserId IN (SELECT CustomerUserID FROM #OrderInfoOUT = OrderInfo))';
SET #SQL =' OrderInfoId, '+
'BorrowerFirstName As ConsumerFirstName, '+
'BorrowerLastName As ConsumerLastName, '+
'RequestedURL, '+
'Requests, '+
#SubQuery+', '+
'u.FirstName +''' '''+ u.LastName As Affiliate, '+
'o.RequestDateTime As DateOfTransaction, '+
'o.RequestIPAddress As OriginatingIPAddress, '+
'o.Requests As Status'+
'from orderInfo o '+
'inner join [User] u on o.AffiliateId = u.UserId';
sp_executesql #SQL, #ParmDefinition, #SubQuery=#S, #OrderIDOUT=OrderID OUTPUT;
Then you can store the results in variables as I've show with OrderInfoOUT
You won't be able to run it this way. You would need something like sp_executesql
I believe there is a mix of concepts in your question: dynamic SQL with table variables.
If you're using SQL Server 2008 or uper, you have a choice to create table variables that keep alives for the period the hosting routine is running.
You can define something similar to this:
DECLARE #UserInfo TABLE
(
FirstName varchar(50) NOT NULL
);
Load the information as follows:
INSERT #UserInfo
SELECT es.FirstName
FROM [User] es
WHERE es.UserId IN (SELECT CustomerUserID FROM OrderInfo)
Finally you can join table variables similar as temporal tables based on your needs.
I need to list all triggers in SQL Server database with table name and table's schema.
I'm almost there with this:
SELECT trigger_name = name, trigger_owner = USER_NAME(uid),table_schema = , table_name = OBJECT_NAME(parent_obj),
isupdate = OBJECTPROPERTY( id, 'ExecIsUpdateTrigger'), isdelete = OBJECTPROPERTY( id, 'ExecIsDeleteTrigger'),
isinsert = OBJECTPROPERTY( id, 'ExecIsInsertTrigger'), isafter = OBJECTPROPERTY( id, 'ExecIsAfterTrigger'),
isinsteadof = OBJECTPROPERTY( id, 'ExecIsInsteadOfTrigger'),
[disabled] = OBJECTPROPERTY(id, 'ExecIsTriggerDisabled')
FROM sysobjects INNER JOIN sysusers ON sysobjects.uid = sysusers.uid
WHERE type = 'TR'
I just need to get the table's schema also.
Here's one way:
SELECT
sysobjects.name AS trigger_name
,USER_NAME(sysobjects.uid) AS trigger_owner
,s.name AS table_schema
,OBJECT_NAME(parent_obj) AS table_name
,OBJECTPROPERTY( id, 'ExecIsUpdateTrigger') AS isupdate
,OBJECTPROPERTY( id, 'ExecIsDeleteTrigger') AS isdelete
,OBJECTPROPERTY( id, 'ExecIsInsertTrigger') AS isinsert
,OBJECTPROPERTY( id, 'ExecIsAfterTrigger') AS isafter
,OBJECTPROPERTY( id, 'ExecIsInsteadOfTrigger') AS isinsteadof
,OBJECTPROPERTY(id, 'ExecIsTriggerDisabled') AS [disabled]
FROM sysobjects
INNER JOIN sysusers
ON sysobjects.uid = sysusers.uid
INNER JOIN sys.tables t
ON sysobjects.parent_obj = t.object_id
INNER JOIN sys.schemas s
ON t.schema_id = s.schema_id
WHERE sysobjects.type = 'TR'
EDIT:
Commented out join to sysusers for query to work on AdventureWorks2008.
SELECT
sysobjects.name AS trigger_name
,USER_NAME(sysobjects.uid) AS trigger_owner
,s.name AS table_schema
,OBJECT_NAME(parent_obj) AS table_name
,OBJECTPROPERTY( id, 'ExecIsUpdateTrigger') AS isupdate
,OBJECTPROPERTY( id, 'ExecIsDeleteTrigger') AS isdelete
,OBJECTPROPERTY( id, 'ExecIsInsertTrigger') AS isinsert
,OBJECTPROPERTY( id, 'ExecIsAfterTrigger') AS isafter
,OBJECTPROPERTY( id, 'ExecIsInsteadOfTrigger') AS isinsteadof
,OBJECTPROPERTY(id, 'ExecIsTriggerDisabled') AS [disabled]
FROM sysobjects
/*
INNER JOIN sysusers
ON sysobjects.uid = sysusers.uid
*/
INNER JOIN sys.tables t
ON sysobjects.parent_obj = t.object_id
INNER JOIN sys.schemas s
ON t.schema_id = s.schema_id
WHERE sysobjects.type = 'TR'
EDIT 2: For SQL 2000
SELECT
o.name AS trigger_name
,'x' AS trigger_owner
/*USER_NAME(o.uid)*/
,s.name AS table_schema
,OBJECT_NAME(o.parent_obj) AS table_name
,OBJECTPROPERTY(o.id, 'ExecIsUpdateTrigger') AS isupdate
,OBJECTPROPERTY(o.id, 'ExecIsDeleteTrigger') AS isdelete
,OBJECTPROPERTY(o.id, 'ExecIsInsertTrigger') AS isinsert
,OBJECTPROPERTY(o.id, 'ExecIsAfterTrigger') AS isafter
,OBJECTPROPERTY(o.id, 'ExecIsInsteadOfTrigger') AS isinsteadof
,OBJECTPROPERTY(o.id, 'ExecIsTriggerDisabled') AS [disabled]
FROM sysobjects AS o
/*
INNER JOIN sysusers
ON sysobjects.uid = sysusers.uid
*/
INNER JOIN sysobjects AS o2
ON o.parent_obj = o2.id
INNER JOIN sysusers AS s
ON o2.uid = s.uid
WHERE o.type = 'TR'
Here you go.
SELECT
[so].[name] AS [trigger_name],
USER_NAME([so].[uid]) AS [trigger_owner],
USER_NAME([so2].[uid]) AS [table_schema],
OBJECT_NAME([so].[parent_obj]) AS [table_name],
OBJECTPROPERTY( [so].[id], 'ExecIsUpdateTrigger') AS [isupdate],
OBJECTPROPERTY( [so].[id], 'ExecIsDeleteTrigger') AS [isdelete],
OBJECTPROPERTY( [so].[id], 'ExecIsInsertTrigger') AS [isinsert],
OBJECTPROPERTY( [so].[id], 'ExecIsAfterTrigger') AS [isafter],
OBJECTPROPERTY( [so].[id], 'ExecIsInsteadOfTrigger') AS [isinsteadof],
OBJECTPROPERTY([so].[id], 'ExecIsTriggerDisabled') AS [disabled]
FROM sysobjects AS [so]
INNER JOIN sysobjects AS so2 ON so.parent_obj = so2.Id
WHERE [so].[type] = 'TR'
A couple of things here...
Also I see that you were attempting to pull the parent tables schema information, I believe in order to do so you would also need to join the sysobjects table on itself so that you can correctly get the schema information for the parent table. the query above does this. Also the sysusers table wasn't needed in the results so that Join has been removed.
tested with SQL 2000, SQL 2005, and SQL 2008 R2
You can also get the body of triggers as following:
SELECT o.[name],
c.[text]
FROM sys.objects AS o
INNER JOIN sys.syscomments AS c
ON o.object_id = c.id
WHERE o.[type] = 'TR'
I had the same task recently and I used the following for sql server 2012 db. Use management studio and connect to the database you want to search. Then execute the following script.
Select
[tgr].[name] as [trigger name],
[tbl].[name] as [table name]
from sysobjects tgr
join sysobjects tbl
on tgr.parent_obj = tbl.id
WHERE tgr.xtype = 'TR'
SELECT
ServerName = ##servername,
DatabaseName = db_name(),
SchemaName = isnull( s.name, '' ),
TableName = isnull( o.name, 'DDL Trigger' ),
TriggerName = t.name,
Defininion = object_definition( t.object_id )
FROM sys.triggers t
LEFT JOIN sys.all_objects o
ON t.parent_id = o.object_id
LEFT JOIN sys.schemas s
ON s.schema_id = o.schema_id
ORDER BY
SchemaName,
TableName,
TriggerName
Use this query :
SELECT OBJECT_NAME(parent_id) as Table_Name, * FROM [Database_Name].sys.triggers
It's simple and useful.
And what do you think about this: Very short and neat :)
SELECT OBJECT_NAME(parent_id) Table_or_ViewNM,
name TriggerNM,
is_instead_of_trigger,
is_disabled
FROM sys.triggers
WHERE parent_class_desc = 'OBJECT_OR_COLUMN'
ORDER BY OBJECT_NAME(parent_id),
Name ;
SELECT
sysobjects.name AS trigger_name ,OBJECT_NAME(parent_obj) AS table_name ,s.name AS table_schema
,USER_NAME(sysobjects.uid) AS trigger_owner
,OBJECTPROPERTY( id, 'ExecIsUpdateTrigger') AS isupdate
,OBJECTPROPERTY( id, 'ExecIsDeleteTrigger') AS isdelete
,OBJECTPROPERTY( id, 'ExecIsInsertTrigger') AS isinsert
,OBJECTPROPERTY( id, 'ExecIsAfterTrigger') AS isafter
,OBJECTPROPERTY( id, 'ExecIsInsteadOfTrigger') AS isinsteadof
,OBJECTPROPERTY(id, 'ExecIsTriggerDisabled') AS [disabled]
FROM sysobjects
INNER JOIN sysusers
ON sysobjects.uid = sysusers.uid
INNER JOIN sys.tables t
ON sysobjects.parent_obj = t.object_id
INNER JOIN sys.schemas s
ON t.schema_id = s.schema_id
WHERE sysobjects.type = 'TR'
this working for me
This is what I use (usually wrapped in something I stuff in Model):
Select
[Parent] = Left((Case When Tr.Parent_Class = 0 Then '(Database)' Else Object_Name(Tr.Parent_ID) End), 32),
[Schema] = Left(Coalesce(Object_Schema_Name(Tr.Object_ID), '(None)'), 16),
[Trigger name] = Left(Tr.Name, 32),
[Type] = Left(Tr.Type_Desc, 3), -- SQL or CLR
[MS?] = (Case When Tr.Is_MS_Shipped = 1 Then 'X' Else ' ' End),
[On?] = (Case When Tr.Is_Disabled = 0 Then 'X' Else ' ' End),
[Repl?] = (Case When Tr.Is_Not_For_Replication = 0 Then 'X' Else ' ' End),
[Event] = Left((Case When Tr.Parent_Class = 0
Then (Select Top 1 Left(Te.Event_Group_Type_Desc, 40)
From Sys.Trigger_Events As Te
Where Te.Object_ID = Tr.Object_ID)
Else ((Case When Tr.Is_Instead_Of_Trigger = 1 Then 'Instead Of ' Else 'After ' End)) +
SubString(Cast((Select [text()] = ', ' + Left(Te.Type_Desc, 1) + Lower(SubString(Te.Type_Desc, 2, 32)) +
(Case When Te.Is_First = 1 Then ' (First)' When Te.Is_Last = 1 Then ' (Last)' Else '' End)
From Sys.Trigger_Events As Te
Where Te.Object_ID = Tr.Object_ID
Order By Te.[Type]
For Xml Path ('')) As Character Varying), 3, 60) End), 60)
-- If you like:
-- , [Get text with] = 'Select Object_Definition(' + Cast(Tr.Object_ID As Character Varying) + ')'
From
Sys.Triggers As Tr
Order By
Tr.Parent_Class, -- database triggers first
Parent -- alphabetically by parent
As you see it is a skosh more McGyver, but I think it's worth it:
Parent Schema Trigger name Type MS? On? Repl? Event
-------------------------------- ---------------- -------------------------------- ---- ---- ---- ----- -----------------------------------------
(Database) (None) ddlDatabaseTriggerLog SQL X DDL_DATABASE_LEVEL_EVENTS
Employee HumanResources dEmployee SQL X Instead Of Delete
Person Person iuPerson SQL X After Insert, Update
PurchaseOrderDetail Purchasing iPurchaseOrderDetail SQL X X After Insert
PurchaseOrderDetail Purchasing uPurchaseOrderDetail SQL X X After Update
PurchaseOrderHeader Purchasing uPurchaseOrderHeader SQL X X After Update
SalesOrderDetail Sales iduSalesOrderDetail SQL X X After Insert, Update, Delete
SalesOrderHeader Sales uSalesOrderHeader SQL X After Update (First)
Vendor Purchasing dVendor SQL X Instead Of Delete
WorkOrder Production iWorkOrder SQL X X After Insert
WorkOrder Production uWorkOrder SQL X X After Update
(Scroll right to see the final and most useful column)
Use This Query :
SELECT
DB_NAME() AS DataBaseName,
S.Name AS SchemaName,
T.name AS TableName,
dbo.SysObjects.Name AS TriggerName,
dbo.sysComments.Text AS SqlContent,
FROM dbo.SysObjects
INNER JOIN dbo.sysComments ON dbo.SysObjects.ID = dbo.sysComments.ID
INNER JOIN sys.tables AS T ON sysobjects.parent_obj = t.object_id
INNER JOIN sys.schemas AS S ON t.schema_id = s.schema_id
WHERE dbo.SysObjects.xType = 'TR'
AND dbo.SysObjects.Name LIKE 'Permit_AfterInsert' ---- <----- HERE
this may help.
SELECT DISTINCT o.[name] AS [Table]
FROM [sysobjects] o
JOIN [sysobjects] tr
ON o.[id] = tr.[parent_obj]
WHERE tr.[type] = 'tr'
ORDER BY [Table]
Get a list of tables and all their triggers.
SELECT DISTINCT o.[name] AS [Table], tr.[name] AS [Trigger]
FROM [sysobjects] o
JOIN [sysobjects] tr
ON o.[id] = tr.[parent_obj]
WHERE tr.[type] = 'tr'
ORDER BY [Table], [Trigger]
The just above code is incorrect as shown:
SELECT
sysobjects.name AS trigger_name
--,USER_NAME(sysobjects.uid) AS trigger_owner
--,s.name AS table_schema
--,OBJECT_NAME(parent_obj) AS table_name
--,OBJECTPROPERTY( id, 'ExecIsUpdateTrigger') AS isupdate
--,OBJECTPROPERTY( id, 'ExecIsDeleteTrigger') AS isdelete
--,OBJECTPROPERTY( id, 'ExecIsInsertTrigger') AS isinsert
--,OBJECTPROPERTY( id, 'ExecIsAfterTrigger') AS isafter
--,OBJECTPROPERTY( id, 'ExecIsInsteadOfTrigger') AS isinsteadof
--,OBJECTPROPERTY(id, 'ExecIsTriggerDisabled') AS [disabled]
FROM sysobjects
/*
INNER JOIN sysusers
ON sysobjects.uid = sysusers.uid
*/
INNER JOIN sys.tables t
ON sysobjects.parent_obj = t.object_id
INNER JOIN sys.schemas s
ON t.schema_id = s.schema_id
WHERE sysobjects.type = 'TR'
EXCEPT
SELECT OBJECT_NAME(parent_id) as Table_Name FROM sys.triggers
C# Cribs: I ended up with this super generic one liner. Hope this is useful to both the original poster and/or people who just typed the same question I did into Google:
SELECT TriggerRecord.name as TriggerName,ParentRecord.name as ForTableName
FROM sysobjects TriggerRecord
INNER JOIN sysobjects ParentRecord ON TriggerRecord.parent_obj=ParentRecord.id
WHERE TriggerRecord.xtype='TR'
Query Characteristics:
Usable with any SQL database (i.e. Initial Catalog)
Self explanatory
One single statement
Pasteable directly into most IDE's for most languages
Necromancing.
Just posting because all solutions so far fall a bit short of completeness.
SELECT
sch.name AS trigger_table_schema
,systbl.name AS trigger_table_name
,systrg.name AS trigger_name
,sysm.definition AS trigger_definition
,systrg.is_instead_of_trigger
-- https://stackoverflow.com/questions/5340638/difference-between-a-for-and-after-triggers
-- Difference between a FOR and AFTER triggers?
-- CREATE TRIGGER trgTable on dbo.Table FOR INSERT,UPDATE,DELETE
-- Is the same as
-- CREATE TRIGGER trgTable on dbo.Table AFTER INSERT,UPDATE,DELETE
-- An INSTEAD OF trigger is different, and fires before and instead of the insert
-- and can be used on views, in order to insert the appropriate values into the underlying tables.
-- AFTER specifies that the DML trigger is fired only when all operations
-- specified in the triggering SQL statement have executed successfully.
-- All referential cascade actions and constraint checks also must succeed before this trigger fires.
-- AFTER is the default when FOR is the only keyword specified.
,CASE WHEN systrg.is_instead_of_trigger = 1 THEN 0 ELSE 1 END AS is_after_trigger
,systrg.is_not_for_replication
,systrg.is_disabled
,systrg.create_date
,systrg.modify_date
,CASE WHEN systrg.parent_class = 1 THEN 'TABLE' WHEN systrg.parent_class = 0 THEN 'DATABASE' END trigger_class
,CASE
WHEN systrg.[type] = 'TA' then 'Assembly (CLR) trigger'
WHEN systrg.[type] = 'TR' then 'SQL trigger'
ELSE ''
END AS trigger_type
-- https://dataedo.com/kb/query/sql-server/list-triggers
-- ,(CASE WHEN objectproperty(systrg.object_id, 'ExecIsUpdateTrigger') = 1
-- THEN 'UPDATE ' ELSE '' END
-- + CASE WHEN objectproperty(systrg.object_id, 'ExecIsDeleteTrigger') = 1
-- THEN 'DELETE ' ELSE '' END
-- + CASE WHEN objectproperty(systrg.object_id, 'ExecIsInsertTrigger') = 1
-- THEN 'INSERT' ELSE '' END
-- ) AS trigger_event
,
(
STUFF
(
(
SELECT
', ' + type_desc AS [text()]
-- STRING_AGG(type_desc, ', ') AS foo
FROM sys.events AS syse
WHERE syse.object_id = systrg.object_id
FOR XML PATH(''), TYPE
-- GROUP BY syse.object_id
).value('.[1]', 'nvarchar(MAX)')
, 1, 2, ''
)
) AS trigger_event_groups
-- ,CASE WHEN systrg.parent_class = 1 THEN 'TABLE' WHEN systrg.parent_class = 0 THEN 'DATABASE' END trigger_class
,'DROP TRIGGER "' + sch.name + '"."' + systrg.name + '"; ' AS sql
-- ,systrg.*
FROM sys.triggers AS systrg
LEFT JOIN sys.sql_modules AS sysm
ON sysm.object_id = systrg.object_id
-- sys.objects for view triggers
-- LEFT JOIN sys.objects AS systbl ON systbl.object_id = systrg.object_id
-- inner join if you only want table-triggers
LEFT JOIN sys.tables AS systbl ON systbl.object_id = systrg.parent_id
LEFT JOIN sys.schemas AS sch
ON sch.schema_id = systbl.schema_id
WHERE (1=1)
-- AND sch.name IS NOT NULL
-- AND sch.name IS NULL
-- AND sch.name = 'dbo'
-- And here, exclude some triggers with a certain naming schema
/*
AND
(
-- systbl.name IS NULL
-- OR
NOT
(
systrg.name = 'TRG_' + systbl.name + '_INSERT_History'
OR
systrg.name = 'TRG_' + systbl.name + '_UPDATE_History'
OR
systrg.name = 'TRG_' + systbl.name + '_DELETE_History'
)
)
*/
ORDER BY
sch.name
,systbl.name
,systrg.name
If you are looking for ALL triggers, remember MS-SQL has both SQL-based triggers (sysobjects.type = 'TR') and CLR-based triggers (sysobjects.type = 'TA').
No need to join with other tables... all info can be obtained from sys.objects.
SELECT name as trigger_name
, object_name(parent_obj) as tableName
, object_schema_name(parent_obj) as schemaName
,OBJECTPROPERTY( id, 'ExecIsUpdateTrigger') AS isupdate
,OBJECTPROPERTY( id, 'ExecIsDeleteTrigger') AS isdelete
,OBJECTPROPERTY( id, 'ExecIsInsertTrigger') AS isinsert
,OBJECTPROPERTY( id, 'ExecIsAfterTrigger') AS isafter
,OBJECTPROPERTY( id, 'ExecIsInsteadOfTrigger') AS isinsteadof
,OBJECTPROPERTY(id, 'ExecIsTriggerDisabled') AS [disabled]
FROM sysobjects s
WHERE s.type = 'TR'
SELECT tbl.name as Table_Name,trig.name as Trigger_Name,trig.is_disabled
FROM [sys].[triggers] as trig inner join sys.tables as tbl on
trig.parent_id = tbl.object_id
CREATE TABLE [dbo].[VERSIONS](
[ID] [uniqueidentifier] NOT NULL,
[DATE] [varchar](100) NULL,
[SERVER] [varchar](100) NULL,
[DATABASE] [varchar](100) NULL,
[USER] [varchar](100) NULL,
[OBJECT] [varchar](100) NULL,
[ACTION] [varchar](100) NULL,
[CODE] [varchar](max) NULL,
CONSTRAINT [PK_VERSIONS] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[VERSIONS] ADD CONSTRAINT [DF_VERSIONS_ID] DEFAULT (newid()) FOR [ID]
GO
DROP TRIGGER [DB_VERSIONS_TRIGGER] ON ALL SERVER
CREATE TRIGGER [DB_VERSIONS_TRIGGER] ON ALL SERVER FOR CREATE_PROCEDURE, ALTER_PROCEDURE, DROP_PROCEDURE,
CREATE_TRIGGER, ALTER_TRIGGER, DROP_TRIGGER, CREATE_FUNCTION, ALTER_FUNCTION, DROP_FUNCTION, CREATE_VIEW, ALTER_VIEW,
DROP_VIEW, CREATE_TABLE, ALTER_TABLE, DROP_TABLE
AS
SET NOCOUNT ON SET XACT_ABORT OFF;
BEGIN
TRY
DECLARE #DATA XML = EVENTDATA()
DECLARE #SERVER VARCHAR(100) = #DATA.value('(EVENT_INSTANCE/ServerName)[1]','VARCHAR(100)')
DECLARE #DATABASE VARCHAR(100) = #DATA.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'VARCHAR(100)')
DECLARE #USER VARCHAR(100) = #DATA.value('(/EVENT_INSTANCE/LoginName)[1]','VARCHAR(100)')
DECLARE #OBJECT VARCHAR(100) = #DATA.value('(EVENT_INSTANCE/ObjectName)[1]','VARCHAR(100)')
DECLARE #ACTION VARCHAR(100) = #DATA.value('(/EVENT_INSTANCE/EventType)[1]','VARCHAR(100)')
DECLARE #CODE VARCHAR(MAX) = #DATA.value('(/EVENT_INSTANCE//TSQLCommand)[1]','VARCHAR(MAX)' )
IF OBJECT_ID('DB_VERSIONS.dbo.VERSIONS') IS NOT NULL
BEGIN
INSERT INTO [DB_VERSIONS].[dbo].[VERSIONS]([SERVER], [DATABASE], [USER], [OBJECT], [ACTION], [DATE], [CODE]) VALUES (#SERVER, #DATABASE, #USER, #OBJECT, #ACTION, getdate(), ISNULL(#CODE, 'NA'))
END
END
TRY
BEGIN
CATCH
END
CATCH
RETURN
SELECT
OBJECT_NAME(PARENT_OBJECT_ID) AS PARENT_TABLE,
OBJECT_NAME(OBJECT_ID) TRIGGER_TABLE,
*
FROM
SYS.OBJECTS
WHERE TYPE = 'TR'
One difficulty is that the text, or description has line feeds. My clumsy kludge, to get it in something more tabular, is to add an HTML literal to the SELECT clause, copy and paste everything to notepad, save with an html extension, open in a browser, then copy and paste to a spreadsheet.
example
SELECT obj.NAME AS TBL,trg.name,sm.definition,'<br>'
FROM SYS.OBJECTS obj
LEFT JOIN (SELECT trg1.object_id,trg1.parent_object_id,trg1.name FROM sys.objects trg1 WHERE trg1.type='tr' AND trg1.name like 'update%') trg
ON obj.object_id=trg.parent_object_id
LEFT JOIN (SELECT sm1.object_id,sm1.definition FROM sys.sql_modules sm1 where sm1.definition like '%suser_sname()%') sm ON trg.object_id=sm.object_id
WHERE obj.type='u'
ORDER BY obj.name;
you may still need to fool around with tabs to get the description into one field, but at least it'll be on one line, which I find very helpful.