×

Two Ways To Get Record Counts for All Tables in a Database

Introduction

When working with databases – especially during migration or maintenance tasks – it's crucial to understand the size and scope of your data. One fundamental metric is knowing how many records exist in each table. This article explores 2 straightforward methods to obtain record counts across all tables in a SQL Server database, providing database administrators and developers with practical solutions for this common requirement.

The 2 Methods

We are looking to get a row count for every table in the database. There is no magic shortcut here; to find the row count, you need to query the table.

The 2 methods that we will examine are using INFORMATION_SCHEMA along with a cursor and dynamic SQL and using the sp_MSforeachtable procedure to do the same thing.

Both methods approach the data in the same way: they assemble a list of tables and execute a statement against each one. Neither method has any great advantage over the other as far as timing, but the sp_MSforeachtable requires only one statement to complete.

Setting Up

We are going to create 2 temporary tables; one to hold information from each method. Because this article is not about best practices with temporary tables or dynamic SQL, we are going to use global temporary tables to simplify what we are doing. 

SET NOCOUNT ON

DROP TABLE IF EXISTS ##RowCountByCursor
CREATE TABLE ##RowCoUntByCursor(TableName VARCHAR(250), TotalRows BIGINT)

DROP TABLE IF EXISTS ##RowCountByForEach
CREATE TABLE ##RowCountByForEach(TableName VARCHAR(250), TotalRows BIGINT)

DECLARE @ObjectName VARCHAR(150)
DECLARE @SQL NVARCHAR(MAX)

 

Using INFORMATION_SCHEMA, a Cursor, and Dynamic SQL

The first method will create a cursor of table names in the database and iterate through it. We are selecting the schema and table names and concatenating them together to make the dynamic SQL easier to write.

DECLARE curTables CURSOR LOCAL FOR
SELECT CONCAT('[',t.TABLE_SCHEMA, '].[', t.TABLE_NAME, ']')
FROM INFORMATION_SCHEMA.TABLES t
WHERE t.TABLE_TYPE = 'BASE TABLE'

OPEN curTables

FETCH NEXT FROM curTables INTO @ObjectName
WHILE @@FETCH_STATUS = 0
BEGIN

	SET @SQL = 'INSERT INTO ##RowCountByCursor(TableName, TotalRows) SELECT '''+ @ObjectName + ''', CAST(Count(1) as BigInt) FROM ' + @ObjectName
	EXEC sp_executesql @SQL

	FETCH NEXT FROM curTables INTO @ObjectName
END
CLOSE curTables
DEALLOCATE curTables

For each table in the database, the code inserts a record in the temporary table with the object name and the count of rows. 

Using sp_MSforeachtable

The built-in system-stored procedure sp_MSforeachtable does the same thing as the code above, but in one line. It executes the SQL passed to it against every table in the database. The question marks in the statement represent the table name that it is currently executing for.

EXEC dbo.sp_MSforeachtable 'INSERT INTO ##RowCountByForEach(TableName, TotalRows) SELECT ''?'' TableName, CAST(Count(1) as BigInt) NumRecords FROM ?'

 

The Results

Querying each of the tables produces an identical record set:

SELECT * FROM ##RowCountByCursor ORDER BY TableName
SELECT * FROM ##RowCountByForEach ORDER BY TableName

 

Table Name Table Rows
Lucy 0
Schroeder 1637
CharlieBrown 76224
Sally 1109
Violet 1109
Patty 62
Shermy 3108
Snoopy 28
Woodstock 1366278

 

Table Name Table Rows
Lucy 0
Schroeder 1637
CharlieBrown 76224
Sally 1109
Violet 1109
Patty 62
Shermy 3108
Snoopy 28
Woodstock 1366278

 

Both methods return the same information in a similar time frame. You can either get record counts using the INFORMATION_SCHEMA to build query strings, or use sp_MSforeachtable to cut down on what you need to program.

Laura MossCore Contributor

Laura Moss is a senior software engineer with Marathon Consulting. As a data wrangler, she specializes in data warehouse architecture and moving data between systems. Her inbox is always empty.