Zapytanie o listę liczby rekordów w każdej tabeli w bazie danych


196

Jak wyświetlić liczbę wierszy każdej tabeli w bazie danych. Jakiś odpowiednik

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

Zamieszczę rozwiązanie, ale inne podejścia są mile widziane

Odpowiedzi:


311

Jeśli używasz programu SQL Server 2005 i nowszych wersji, możesz także użyć tego:

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) 

Moim zdaniem jest łatwiejszy w obsłudze niż sp_msforeachtablewyjście.


1
Masz pojęcie, dlaczego filtruje tabele o nazwie zaczynającej się od „dt”? Widziałem ten skrypt w całej sieci, ale nie wyjaśniono tych kryteriów. Czy wszyscy jesteśmy trollowani?
Skaue

6
@Skaue: jeśli zainstalujesz funkcję „Diagram bazy danych” w twojej bazie danych, będziesz mieć kilka tabel takich jak dtPropertiesi tak dalej; ponieważ są to tabele „systemowe”, nie chcę o nich raportować.
marc_s

1
Czy w tym skrypcie można poprzedzić tablename nazwą schematu?
gh0st

Z jakiegoś powodu to zapytanie nie zwraca wszystkich tabel. Mam 382 tabele w bazie danych. Ale to zapytanie zwraca tylko 270 wierszy (informacje o tabeli). Po usunięciu warunku where otrzymuję 302 wiersze. Wynika to z faktu, że brakuje niektórych informacji o tabelach w jednej z tabel SYS, więc sprzężenia pomijają je. Baza danych nie zawiera żadnych tabel systemowych.
Ankesh Kushwah

To działa czy możesz go zmodyfikować, aby porównać dwie bazy danych?
sanjeewa

107

Fragment, który znalazłem na stronie http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=21021, który pomógł mi:

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
Podoba mi się to rozwiązanie, chociaż JOINfrom sysobjects t inner join sysindexes i on i.id = t.id and i.indid in (0,1) where t.xtype = 'U'
użyłbym

Wolę też używać instrukcji JOIN, ale opublikowałem fragment kodu, gdy go znalazłem. :)
Erik Anderson

32

Aby uzyskać te informacje w SQL Management Studio, kliknij prawym przyciskiem myszy bazę danych, a następnie wybierz Raporty -> Raporty standardowe -> Wykorzystanie dysku według tabeli.


6
Niedoceniane podejście, to szybko generuje sortowalny raport pokazujący # wierszy i rozmiar danych.
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
To zapytanie zwróci wynik wierszy dla każdego indeksu w każdej tabeli. Dodaj WHERE P.INDEX_ID IN (0,1), aby ograniczyć zestaw wyników zwracanych do stosów lub indeksów klastrowych tylko w razie potrzeby.
Rasmus Remmer Bielidt,

6

Jak widać tutaj, zwróci to poprawne zliczenia, a metody wykorzystujące tabele metadanych zwrócą tylko szacunki.

    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

Brzmi więc to jak kompromis w używaniu nieudokumentowanego stor proc sp_msForEachTable w porównaniu do używania tabel systemowych z czasami nieaktualnymi informacjami. +1 i dzięki za 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'

Wynik:

wprowadź opis zdjęcia tutaj


Potrzebowałem czegoś do Sql Server 2000. To zadziałało. Dzięki!
Alrekr

3

Na szczęście studio zarządzania SQL Server daje podpowiedź, jak to zrobić. Zrób to,

  1. rozpocznij śledzenie programu SQL Server i otwórz aktywność, którą wykonujesz (przefiltruj według identyfikatora logowania, jeśli nie jesteś sam i ustaw nazwę aplikacji na Microsoft SQL Server Management Studio), wstrzymaj śledzenie i odrzuć wszystkie dotychczas zarejestrowane wyniki;
  2. Następnie kliknij tabelę prawym przyciskiem myszy i wybierz właściwość z menu podręcznego;
  3. rozpocznij śledzenie ponownie;
  4. Teraz w SQL Server Management studio wybierz element właściwości magazynu po lewej;

Zatrzymaj śledzenie i zobacz, co TSQL generuje Microsoft.

W prawdopodobnie ostatnim zapytaniu zobaczysz instrukcję zaczynającą się od exec sp_executesql N'SELECT

po skopiowaniu wykonanego kodu do Visual Studio zauważysz, że ten kod generuje wszystkie dane, które inżynierowie z Microsoft zastosowali do wypełnienia okna właściwości.

kiedy wprowadzisz umiarkowane zmiany do tego zapytania, przejdziesz do czegoś takiego:

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

Teraz zapytanie nie jest idealne i możesz je zaktualizować, aby spełniało inne Twoje pytania, chodzi o to, że możesz skorzystać z wiedzy o Microsoft, aby uzyskać dostęp do większości pytań, wykonując dane, które Cię interesują, i śledź TSQL wygenerowany przy użyciu profilera.

Lubię myśleć, że inżynierowie MS wiedzą, jak działa serwer SQL, i wygeneruje TSQL, który działa na wszystkich elementach, z którymi możesz pracować przy użyciu wersji na SSMS, której używasz, więc jest całkiem dobry w wielu wersjach wcześniejszych, bieżących i przyszłość.

I pamiętaj, nie kopiuj, staraj się to zrozumieć, bo w przeciwnym razie możesz skończyć z niewłaściwym rozwiązaniem.

Walter


2

Podejście to wykorzystuje konkatenację łańcuchów, aby dynamicznie wygenerować instrukcję ze wszystkimi tabelami i ich liczbą, podobnie jak w przykładach podanych w pierwotnym pytaniu:

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

Na koniec jest to wykonywane za pomocą 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);

zwróć uwagę, że to rozwiązanie zawiera nazwę schematu (co może być przydatne)
gordon613,


1

Pierwszą rzeczą, jaka przyszła mi do głowy, było użycie sp_msForEachTable

exec sp_msforeachtable 'select count(*) from ?'

która nie zawiera nazw tabel, więc można ją rozszerzyć na

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

Problem polega na tym, że jeśli baza danych ma więcej niż 100 tabel, pojawi się następujący komunikat o błędzie:

Kwerenda przekroczyła maksymalną liczbę zestawów wyników, które można wyświetlić w siatce wyników. Tylko pierwszych 100 zestawów wyników jest wyświetlanych w siatce.

Skończyło się na tym, że użyłem zmiennej tabeli do przechowywania wyników

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

Odpowiedź Zaakceptowany nie działa dla mnie na SQL Azure, tutaj jest jeden , że nie, że to super szybki i zrobił dokładnie to, co chciałem:

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

Ten skrypt sql podaje schemat, nazwę tabeli i liczbę wierszy każdej tabeli w wybranej bazie danych:

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

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

Kolejny sposób to zrobić:

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

Myślę, że najkrótszym, najszybszym i najprostszym sposobem byłoby:

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

Możesz spróbować:

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

Z tego pytania: /dba/114958/list-all-tables-from-all-user-databases/230411#230411

Dodałem liczbę rekordów do odpowiedzi udzielonej przez @Aaron Bertrand, która zawiera listę wszystkich baz danych i wszystkich tabel.

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

Możesz skopiować, wkleić i wykonać ten fragment kodu, aby uzyskać wszystkie liczby rekordów tabeli do tabeli. Uwaga: Kod jest komentowany instrukcjami

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

Przetestowałem ten kod i działa dobrze na SQL Server 2014.


0

Chcę podzielić się tym, co dla mnie działa

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

Baza danych jest hostowana na platformie Azure, a końcowy wynik to: wprowadź opis zdjęcia tutaj

Źródło: https://www.mssqltips.com/sqlservertip/2537/sql-server-row-count-for-all-tables-in-a-database/


-1

Jeśli używasz MySQL> 4.x, możesz użyć tego:

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

Należy pamiętać, że w przypadku niektórych silników pamięci masowej TABLE_ROWS jest przybliżeniem.


6
wspomniał o „sql-server” w swoim poście (jako znaczniku), którym jest 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'

Tutaj indid=1oznacza wskaźnik klastrowych i indid=0jest kupa


4
Cześć i witamy w Stack Overflow. Ta odpowiedź jest identyczna z jednym, który jest rok stary już ... nie było potrzeby, aby umieścić go ponownie.
Ben
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.