Comment lister le nombre de lignes de chaque table dans la base de données. Quelque équivalent de
select count(*) from table1
select count(*) from table2
...
select count(*) from tableN
Je vais poster une solution mais d'autres approches sont les bienvenues
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, il est plus facile à gérer que la sortie sp_msforeachtable
.
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;
Pour obtenir ces informations dans SQL Management Studio, cliquez avec le bouton droit de la souris sur la base de données, puis sélectionnez Rapports -> Rapports standard -> Utilisation du disque par 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;
Comme on le voit ici, ceci retournera des comptes 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
Moyen le plus rapide de rechercher le nombre de lignes de toutes les tables dans 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
sp_MSForEachTable 'DECLARE @t AS VARCHAR(MAX);
SELECT @t = CAST(COUNT(1) as VARCHAR(MAX))
+ CHAR(9) + CHAR(9) + ''?'' FROM ? ; PRINT @t'
Sortie:
La première chose qui me vint à l’esprit fut d’utiliser sp_msForEachTable.
exec sp_msforeachtable 'select count(*) from ?'
cela ne liste pas les noms de table cependant, donc il peut être étendu à
exec sp_msforeachtable 'select parsename(''?'', 1), count(*) from ?'
Le problème ici est que si la base de données a plus de 100 tables, vous obtiendrez le message d'erreur suivant:
La requête a dépassé le maximum nombre d'ensembles de résultats pouvant être affiché dans la grille de résultats. Seulement les 100 premiers ensembles de résultats sont affiché 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
La réponse acceptée ne fonctionnait pas pour moi sur Azure SQL, voici un qui l’a fait, c’est très 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
Heureusement, le studio de gestion SQL Server vous donne un indice sur la façon de procéder. .__ faire ceci,
Suspendez la trace et examinez ce que TSQL est généré par Microsoft.
Dans la dernière requête probablement, vous verrez une instruction 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 renseigner 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. Vous pouvez utiliser les connaissances de Microsoft pour répondre à la plupart de vos questions en exécutant les données qui vous intéressent et en tracer la TSQL générée à l'aide du profileur.
J'aime bien penser que les ingénieurs MS connaissent le fonctionnement du serveur SQL. Il générera une TSQL qui fonctionne avec tous les éléments que vous pouvez utiliser à l'aide de la version sur SSMS que vous utilisez. Il convient donc très bien à une grande variété de versions: futur.
Et rappelez-vous, ne vous contentez pas de copier, essayez de comprendre, sinon vous risqueriez de vous retrouver avec la mauvaise solution.
Walter
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
Vous pouvez copier, coller et exécuter ce morceau de code pour obtenir tous les comptes d'enregistrement 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 bien sur SQL Server 2014.
De cette question: https://dba.stackexchange.com/questions/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;
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
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)
Cette approche utilise la concaténation de chaînes pour produire une instruction avec toutes les tables et leurs nombres de manière dynamique, à l'instar des 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...
Finalement, ceci 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);
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 faire ceci:
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