Interrogazione per elencare il numero di record in ciascuna tabella in un database


198

Come elencare il conteggio delle righe di ogni tabella nel database. Qualche equivalente di

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

Pubblicherò una soluzione ma altri approcci sono ben accetti

Risposte:


313

Se si utilizza SQL Server 2005 e versioni successive, è possibile utilizzare anche questo:

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) 

A mio avviso, è più facile da gestire rispetto sp_msforeachtableall'output.


1
Qualche idea sul perché stia filtrando le tabelle con un nome che inizia con "dt"? Ho visto questo script su tutta la rete, ma nessuna spiegazione su tali criteri. Siamo stati tutti trollati?
Skaue,

6
@Skaue: se installi la funzionalità "Database Diagram" in un tuo database, avrai alcune tabelle simili dtPropertiese così via; dal momento che quelle sono tabelle "di sistema", non voglio riferirle.
marc_s,

1
Possibilità di aggiungere il prefisso al tablename con il nome dello schema in questo script?
gh0st,

Per qualche motivo questa query non sta restituendo tutte le tabelle. Ho 382 tabelle in un database. Ma questa query restituisce solo 270 righe (informazioni sulla tabella). Dopo aver rimosso la condizione where ottengo 302 righe. È dovuto al fatto che alcune delle informazioni sulle tabelle mancano in una delle tabelle SYS, quindi i join le omettono. Il database non contiene alcuna tabella di sistema.
Ankesh Kushwah,

Questo sta funzionando. puoi modificarlo per confrontare due database.
sanjeewa,

107

Uno snippet che ho trovato su http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=21021 che mi ha aiutato:

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;

5
Mi piace questa soluzione, anche se JOINfrom sysobjects t inner join sysindexes i on i.id = t.id and i.indid in (0,1) where t.xtype = 'U'
userei

Preferisco usare anche le istruzioni JOIN ma ho pubblicato lo snippet di codice come l'ho trovato. :)
Erik Anderson,

32

Per ottenere tali informazioni in SQL Management Studio, fare clic con il pulsante destro del mouse sul database, quindi selezionare Rapporti -> Rapporti standard -> Utilizzo del disco per tabella.


6
Approccio sottovalutato, questo genera rapidamente un rapporto ordinabile che mostra # righe e dimensioni dei dati.
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;

3
Questa query restituirà un risultato di righe per ciascun indice su ogni tabella. Aggiungi un WHERE P.INDEX_ID IN (0,1) per limitare il set di risultati di ritorno a heap o indici cluster solo dove appropriato.
Rasmus Remmer Bielidt,

6

Come visto qui, questo restituirà conteggi corretti, in cui i metodi che utilizzano le tabelle dei metadati restituiranno solo stime.

    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

Quindi sembra un compromesso dell'utilizzo di stor proc sp_msForEachTable stor non documentato rispetto all'utilizzo di tabelle di sistema con informazioni talvolta non aggiornate. +1 e grazie per il link
kristof,

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

Produzione:

inserisci qui la descrizione dell'immagine


Avevo bisogno di qualcosa per SQL Server 2000. Funzionava. Grazie!
Alrekr,

3

Fortunatamente lo studio di gestione di SQL Server ti dà un suggerimento su come farlo. Fai questo,

  1. avviare una traccia di SQL Server e aprire l'attività in corso (filtrare in base all'ID di accesso se non si è soli e impostare il nome dell'applicazione su Microsoft SQL Server Management Studio), mettere in pausa la traccia e scartare tutti i risultati registrati fino ad ora;
  2. Quindi, fai clic con il pulsante destro del mouse su una tabella e seleziona la proprietà dal menu a comparsa;
  3. ricominciare la traccia;
  4. Ora in SQL Server Management Studio selezionare l'elemento della proprietà di archiviazione a sinistra;

Metti in pausa la traccia e dai un'occhiata a ciò che TSQL viene generato da Microsoft.

Nell'ultima query probabilmente vedrai un'istruzione che inizia con exec sp_executesql N'SELECT

quando copi il codice eseguito su Visual Studio noterai che questo codice genera tutti i dati utilizzati dagli ingegneri di Microsoft per popolare la finestra delle proprietà.

quando si apportano modifiche moderate a quella query si arriva a qualcosa del genere:

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

Ora la query non è perfetta e potresti aggiornarla per soddisfare altre domande che potresti avere, il punto è che puoi usare la conoscenza di Microsoft per ottenere la maggior parte delle domande che hai eseguendo i dati che ti interessano e traccia il TSQL generato usando il profiler.

Mi piace pensare che gli ingegneri MS sappiano come funziona il server SQL e genererà TSQL che funziona su tutti gli elementi con cui puoi lavorare utilizzando la versione su SSMS che stai utilizzando, quindi è abbastanza buono su una grande varietà di versioni prerviouse, current e futuro.

E ricorda, non limitarti a copiare, prova anche a capirlo, altrimenti potresti finire con la soluzione sbagliata.

Walter


2

Questo approccio utilizza la concatenazione di stringhe per produrre un'istruzione con tutte le tabelle e i loro conteggi in modo dinamico, come nell'esempio o negli esempi forniti nella domanda originale:

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

Infine questo viene eseguito con 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);

nota che questa soluzione include il nome dello schema (che può essere utile)
gordon613


1

La prima cosa che mi è venuta in mente è stata usare sp_msForEachTable

exec sp_msforeachtable 'select count(*) from ?'

che però non elenca i nomi delle tabelle, quindi può essere esteso a

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

Il problema qui è che se il database ha più di 100 tabelle riceverai il seguente messaggio di errore:

La query ha superato il numero massimo di set di risultati che possono essere visualizzati nella griglia dei risultati. Nella griglia vengono visualizzati solo i primi 100 set di risultati.

Quindi ho finito per usare la variabile table per memorizzare i risultati

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

1

La risposta accettata non ha funzionato per me su Azure SQL, eccone una , è super veloce e ha fatto esattamente quello che volevo:

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

1

Questo script sql fornisce lo schema, il nome della tabella e il conteggio delle righe di ciascuna tabella in un database selezionato:

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

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

Un altro modo per farlo:

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

0

Penso che il modo più breve, veloce e semplice sarebbe:

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

0

Puoi provare questo:

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)

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

0

Da questa domanda: /dba/114958/list-all-tables-from-all-user-d database / 230411#230411

Ho aggiunto il conteggio dei record alla risposta fornita da @Aaron Bertrand che elenca tutti i database e tutte le tabelle.

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;

0

È possibile copiare, incollare ed eseguire questo pezzo di codice per ottenere tutti i conteggi dei record di tabella in una tabella. Nota: il codice è commentato con le istruzioni

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

Ho testato questo codice e funziona benissimo su SQL Server 2014.


0

Voglio condividere ciò che funziona per 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

Il database è ospitato in Azure e il risultato finale è: inserisci qui la descrizione dell'immagine

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


-1

Se usi MySQL> 4.x puoi usare questo:

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

Tieni presente che per alcuni motori di archiviazione, TABLE_ROWS è un'approssimazione.


6
ha menzionato "sql-server" nel suo post (come tag) che è 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'

Qui indid=1significa un indice CLUSTER ed indid=0è un HEAP


4
Ciao e benvenuto su Stack Overflow. Questa risposta è identica a quella che ha già un anno ... non è stato necessario pubblicarla di nuovo.
Ben
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.