Requête pour répertorier le nombre d'enregistrements dans chaque table d'une base de données

198

Comment répertorier le nombre de lignes de chaque table dans la base de données. Un équivalent de

select count(*) from table1
select count(*) from table2
...
select count(*) from tableN

Je posterai une solution mais d'autres approches sont les bienvenues

kristof
la source

Réponses:

313

Si vous utilisez SQL Server 2005 et versions ultérieures, vous pouvez également utiliser ceci:

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) 

À mon avis, c'est plus facile à gérer que la sp_msforeachtablesortie.

marc_s
la source
1
Une idée pourquoi il filtre les tables avec un nom commençant par "dt"? J'ai vu ce script partout sur le net, mais aucune explication sur ce critère. Sommes-nous tous trollés?
Skaue
6
@Skaue: si vous installez la fonctionnalité "Diagramme de base de données" dans une de vos bases de données, alors vous aurez des tableaux comme dtPropertieset ainsi de suite; puisque ce sont des tables "système", je ne veux pas en faire rapport.
marc_s
1
Possibilité de préfixer le nom de la table avec le nom du schéma dans ce script?
gh0st
Pour une raison quelconque, cette requête ne renvoie pas toutes les tables. J'ai 382 tables dans une base de données. Mais cette requête ne renvoie que 270 lignes (informations de table). Après avoir supprimé la condition Where, j'obtiens 302 lignes. Est-ce dû au fait que certaines informations sur les tables manquent dans l'une des tables SYS, les jointures les omettent. La base de données ne contient aucune table système.
Ankesh Kushwah
Cela fonctionne. pouvez-vous le modifier pour comparer deux bases de données.
sanjeewa
107

Un extrait que j'ai trouvé sur http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=21021 qui m'a aidé:

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;
Erik Anderson
la source
5
J'aime cette solution, bien que j'utilise la JOINsyntaxefrom sysobjects t inner join sysindexes i on i.id = t.id and i.indid in (0,1) where t.xtype = 'U'
Shnugo
Je préfère également utiliser les instructions JOIN, mais j'ai publié l'extrait de code tel que je l'ai trouvé. :)
Erik Anderson
32

Pour obtenir ces informations dans SQL Management Studio, cliquez avec le bouton droit sur la base de données, puis sélectionnez Rapports -> Rapports standard -> Utilisation du disque par table.

petra
la source
6
Approche sous-estimée, cela génère rapidement un rapport triable montrant # lignes et la taille des données.
tbone
8
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;
ANG
la source
3
Cette requête renvoie un résultat de lignes pour chaque index de chaque table. Ajoutez un WHERE P.INDEX_ID IN (0,1) pour limiter le jeu de résultats de retour aux tas ou aux index cluster uniquement lorsque cela est approprié.
Rasmus Remmer Bielidt
6

Comme on le voit ici, cela retournera des nombres corrects, où les méthodes utilisant les tables de métadonnées ne renverront que des estimations.

    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
KM.
la source
Cela ressemble donc à un compromis entre l'utilisation de stor proc non documenté sp_msForEachTable et l'utilisation de tables système avec parfois des informations peu actualisées. +1 et merci pour le lien
kristof
3
sp_MSForEachTable 'DECLARE @t AS VARCHAR(MAX); 
SELECT @t = CAST(COUNT(1) as VARCHAR(MAX)) 
+ CHAR(9) + CHAR(9) + ''?'' FROM ? ; PRINT @t'

Production:

entrez la description de l'image ici

Rikin Patel
la source
J'avais besoin de quelque chose pour Sql Server 2000. Cela a fonctionné. Merci!
Alrekr
3

Heureusement, le studio de gestion SQL Server vous donne un indice sur la façon de procéder. Faites ça,

  1. démarrez une trace SQL Server et ouvrez l'activité que vous faites (filtrez par votre ID de connexion si vous n'êtes pas seul et définissez le nom de l'application sur Microsoft SQL Server Management Studio), suspendez la trace et supprimez tous les résultats que vous avez enregistrés jusqu'à présent;
  2. Ensuite, cliquez avec le bouton droit sur une table et sélectionnez une propriété dans le menu contextuel;
  3. recommencez la trace;
  4. Maintenant, dans SQL Server Management Studio, sélectionnez l'élément de propriété de stockage sur la gauche;

Arrêtez la trace et regardez ce que TSQL est généré par Microsoft.

Dans la dernière requête probablement, vous verrez une déclaration commençant par exec sp_executesql N'SELECT

lorsque vous copiez le code exécuté dans Visual Studio, vous remarquerez que ce code génère toutes les données utilisées par les ingénieurs de Microsoft pour remplir la fenêtre de propriétés.

lorsque vous apportez des modifications modérées à cette requête, vous obtiendrez quelque chose comme ceci:

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

Maintenant, la requête n'est pas parfaite et vous pouvez la mettre à jour pour répondre à d'autres questions que vous pourriez avoir, le fait est que vous pouvez utiliser les connaissances de Microsoft pour accéder à la plupart des questions que vous avez en exécutant les données qui vous intéressent et tracer le TSQL généré à l'aide du profileur.

J'aime penser que les ingénieurs MS savent comment fonctionne SQL Server et qu'il générera TSQL qui fonctionne sur tous les éléments avec lesquels vous pouvez travailler en utilisant la version sur SSMS que vous utilisez, donc c'est assez bon sur une grande variété de versions prerviouse, actuelles et futur.

Et rappelez-vous, ne vous contentez pas de copier, essayez de le comprendre ainsi sinon vous pourriez vous retrouver avec la mauvaise solution.

Walter

Walter Verhoeven
la source
2

Cette approche utilise la concaténation de chaînes pour produire une instruction avec toutes les tables et leurs nombres de manière dynamique, comme les exemples donnés dans la question d'origine:

          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...

Enfin, cela est exécuté avec 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);
Shnugo
la source
notez que cette solution inclut le nom du schéma (qui peut être utile)
gordon613
1

La première chose qui m'est venue à l'esprit était d'utiliser sp_msForEachTable

exec sp_msforeachtable 'select count(*) from ?'

qui ne répertorie pas les noms de table, il peut donc être étendu à

exec sp_msforeachtable 'select parsename(''?'', 1),  count(*) from ?'

Le problème ici est que si la base de données contient plus de 100 tables, vous obtiendrez le message d'erreur suivant:

La requête a dépassé le nombre maximal d'ensembles de résultats pouvant être affichés dans la grille de résultats. Seuls les 100 premiers jeux de résultats sont affichés dans la grille.

J'ai donc fini par utiliser une variable de table pour stocker les résultats

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
kristof
la source
1

La réponse acceptée n'a pas fonctionné pour moi sur Azure SQL, en voici une qui l'a fait, elle est super rapide et a fait exactement ce que je voulais:

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
UnionP
la source
1

Ce script SQL donne le schéma, le nom de la table et le nombre de lignes de chaque table dans une base de données sélectionnée:

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

Réf: https://blog.sqlauthority.com/2017/05/24/sql-server-find-row-count-every-table-database-efficiently/

Une autre façon de procéder:

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
rchacko
la source
0

Je pense que le moyen le plus court, le plus rapide et le plus simple serait:

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
sotn
la source
0

Vous pouvez essayer ceci:

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)
Steve Ford
la source
0
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
foluis
la source
0

De cette question: /dba/114958/list-all-tables-from-all-user-databases/230411#230411

J'ai ajouté le nombre d'enregistrements à la réponse fournie par @Aaron Bertrand qui répertorie toutes les bases de données et toutes les 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;
Jeremy F.
la source
0

Vous pouvez copier, coller et exécuter ce morceau de code pour obtenir tous les nombres d'enregistrements de table dans une table. Remarque: Le code est commenté avec des 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

J'ai testé ce code et cela fonctionne très bien sur SQL Server 2014.

Mujtaba
la source
0

Je veux partager ce qui fonctionne pour moi

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

La base de données est hébergée dans Azure et le résultat final est: entrez la description de l'image ici

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

d.danailov
la source
-1

Si vous utilisez MySQL> 4.x, vous pouvez utiliser ceci:

select TABLE_NAME, TABLE_ROWS from information_schema.TABLES where TABLE_SCHEMA="test";

Gardez à l'esprit que pour certains moteurs de stockage, TABLE_ROWS est une approximation.

David Poblador i Garcia
la source
6
il a mentionné "sql-server" dans son article (comme une balise) qui est Microsoft SQL Server
marc_s
-1
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'

Ici indid=1signifie un index CLUSTERED et indid=0est un HEAP

Jyoti prashad chaulkara
la source
4
Salut et bienvenue sur Stack Overflow. Cette réponse est identique à celle qui a déjà un an ... il n'était pas nécessaire de la poster à nouveau.
Ben