kristof
kristof

Reputation: 53854

Query to list number of records in each table in a database

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

Upvotes: 251

Views: 407212

Answers (24)

petra
petra

Reputation: 2792

To get that information in SQL Management Studio, right-click on the database name, then select Reports --> Standard Reports --> Disk Usage by Table.

Upvotes: 50

mediaXpert
mediaXpert

Reputation: 121

This version will give you the count of rows per table and the number of columns as well.

select a.table_name as 'table', a.[rows], COUNT(c.COLUMN_NAME) as 'columns' from (
select distinct schema_name(t.schema_id) as schema_name, t.name as table_name, p.[Rows] as [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
) as a
    INNER JOIN INFORMATION_SCHEMA.COLUMNS AS c ON a.[table_name] = c.TABLE_NAME
group by a.table_name, a.rows
order by a.table_name;

Upvotes: 0

user3820843
user3820843

Reputation:

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;

sample ssms output

Upvotes: 5

Velocedge
Velocedge

Reputation: 1475

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.

Upvotes: 0

Y S CHANDRA SHEKHAR
Y S CHANDRA SHEKHAR

Reputation: 1

        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

Upvotes: 0

d.danailov
d.danailov

Reputation: 9810

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: enter image description here

Credit: https://www.mssqltips.com/sqlservertip/2537/sql-server-row-count-for-all-tables-in-a-database/

Upvotes: 3

Erik Anderson
Erik Anderson

Reputation: 5299

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;

Upvotes: 139

Mujtaba
Mujtaba

Reputation: 369

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.

Upvotes: 0

Jeremy F.
Jeremy F.

Reputation: 1878

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;

Upvotes: 1

rchacko
rchacko

Reputation: 2129

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

Upvotes: 1

foluis
foluis

Reputation: 1048

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

Upvotes: 0

Muhammad Sohail
Muhammad Sohail

Reputation: 878

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

Upvotes: 2

Gottfried Lesigang
Gottfried Lesigang

Reputation: 67331

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);

Upvotes: 3

Steve Ford
Steve Ford

Reputation: 7763

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)

Upvotes: 3

yakya
yakya

Reputation: 5220

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

Upvotes: 0

UnionP
UnionP

Reputation: 1648

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

Upvotes: 1

Walter Verhoeven
Walter Verhoeven

Reputation: 641

Well luckily SQL Server management studio gives you a hint on how to do this. Do this,

  1. 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;
  2. Then, right click a table and select property from the pop up menu;
  3. start the trace again;
  4. 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

Upvotes: 3

Rikin Patel
Rikin Patel

Reputation: 9393

sp_MSForEachTable 'DECLARE @t AS VARCHAR(MAX); 
SELECT @t = CAST(COUNT(1) as VARCHAR(MAX)) 
+ CHAR(9) + CHAR(9) + ''?'' FROM ? ; PRINT @t'

Output:

enter image description here

Upvotes: 3

ANG
ANG

Reputation: 247

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;

Upvotes: 16

marc_s
marc_s

Reputation: 755381

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.

Upvotes: 372

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

Upvotes: -1

KM.
KM.

Reputation: 103697

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

Upvotes: 6

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.

Upvotes: 1

kristof
kristof

Reputation: 53854

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

Upvotes: 2

Related Questions