Подсчет количества строк в нескольких таблицах в одном запросе - PullRequest
2 голосов
/ 15 ноября 2010

У меня есть база данных SQL Server 2005, в которой хранятся данные для нескольких пользователей.Каждая таблица, которая содержит данные, принадлежащие пользователю, имеет столбец с именем OwnerID, который идентифицирует владельца;большинство, но не все таблицы имеют этот столбец.

Я хочу иметь возможность подсчитывать количество строк, «принадлежащих» пользователю в каждой таблице.Другими словами, я хочу запрос, который возвращает имена каждой таблицы, которая содержит столбец OwnerID, и подсчитывает количество строк в каждой таблице, которые соответствуют данному значению OwnerID.

Я могу вернутьтолько имена соответствующих таблиц, использующих этот запрос:

SELECT OBJECT_NAME(object_id) [Table] FROM sys.columns 
    WHERE name = 'OwnerID' ORDER BY OBJECT_NAME(object_id);

Этот запрос возвращает список имен таблиц, подобных этому:

+---------+
|  Table  |
+---------+
| Alpha   |
| Beta    |
| Gamma   |
| ...     |
+---------+

Но возможно ли написать запрос, который можеттакже посчитать количество строк в каждой таблице, которые соответствуют данному OwnerID?т.е.:

+---------+------------+
|  Table  |  RowCount  |
+---------+------------+
| Alpha   | 2042       |
| Beta    | 49         |
| Gamma   | 740        |
| ...     | ...        |
+---------+------------+

Примечание: Список имен таблиц необходимо возвращать динамически, он не подходит для жесткого кодирования имен таблиц в этом запросе.


Редактировать: ответ ...

(Я пока не могу отредактировать ваши ответы, но могу отредактировать свой собственный вопрос, поэтому ставлю его здесь ...)

Damien_The_Unbeliever имел по существу правильный ответ, но SQL Server не допускает конкатенацию строк в операторе exec, поэтому мне пришлось задать запрос до оператора exec.Последний запрос выглядит следующим образом:

DECLARE @OwnerID int;
SET @OwnerID = 1;

DECLARE @ForEachSQL varchar(100);
SET @ForEachSQL = 'INSERT INTO #t(TableName,RowsOwned) SELECT ''?'', COUNT(*) FROM ? WHERE OwnerID = ' + CONVERT(varchar(11), @OwnerID);

CREATE TABLE #t(TableName sysname, RowsOwned int);
EXEC sp_MSforeachtable @ForEachSQL, 
    @whereAnd = 'AND o.id IN (SELECT id FROM syscolumns where name=''OwnerID'')';
SELECT * FROM #t ORDER BY TableName;
DROP TABLE #t;

Ответы [ 4 ]

4 голосов
/ 15 ноября 2010

Вы можете использовать sp_MSForeachtable и параметр @whereand, чтобы указать фильтр, чтобы вы работали только с таблицами со столбцом OwnerID. Создайте временную таблицу и заполните ее для каждой соответствующей таблицы. Что-то вроде:

create table #t(tablename sysname,Cnt int)
sp_MSforeachtable 'insert into #t(tablename,Cnt) select ''?'',COUNT(*) from ?',@whereAnd='and o.id in (select id from syscolumns where name=''OwnerID'')'
select * from #t

Следует упомянуть два основных замечания - во-первых, sp_MSforeachtable является «недокументированным», поэтому вы используете его на свой страх и риск - он может быть внезапно удален из SQL Server любым видом обслуживания или в следующем выпуске.

Во-вторых, наличие динамической схемы обычно признак того, что в моделировании что-то пошло не так - возможно, разделение атрибутов (где продажи за январь и февраль приведены в разных таблицах, даже если они ' логически одно и то же и должно появиться в той же таблице, возможно, с дополнительным столбцом для их различения)


И, конечно же, вы хотите фильтровать на основе определенного clientID, поэтому запрос будет выглядеть так:

'insert into #t(tablename,Cnt) select ''?'',COUNT(*) from ? where OwnerID=' + @OwnerID

(Предполагая, что @OwnerID - искомый владелец, и является int)

1 голос
/ 15 ноября 2010

Вы можете использовать это:

DECLARE @nSQL NVARCHAR(MAX)

SELECT @nSQL = COALESCE(@nSQL + 'UNION ALL ' + CHAR(10), '') 
    + 'SELECT ''' + TABLE_NAME + ''' AS TableName, COUNT(*) FROM ' + QUOTENAME(TABLE_NAME) + CHAR(10)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = 'strKey'

-- This will PRINT out the dynamically generated SQL statement. Just replace this with EXECUTE(@nSQL) when you are happy to run it.
PRINT @nSQL

Обновление: для поиска определенного OwnerId:

DECLARE @nSQL NVARCHAR(MAX)
DECLARE @OwnerId INTEGER
SET @OwnerId = 1

SELECT @nSQL = COALESCE(@nSQL + 'UNION ALL ' + CHAR(10), '') 
        + 'SELECT ''' + TABLE_NAME + ''' AS TableName, COUNT(*) FROM ' + QUOTENAME(TABLE_NAME) + ' WHERE OwnerId = @OwnerId' + CHAR(10)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = 'strKey'

EXECUTE sp_executesql @nSQL, '@OwnerId INTEGER', @OwnerId
1 голос
/ 15 ноября 2010

Это получит информацию от sysindexes.Это может быть немного устаревшим, но даст вам приблизительный подсчет

SELECT 
    [TableName] = so.name, 
    [RowCount] = MAX(si.rows) 
FROM 
    sysobjects so, 
    sysindexes si 
WHERE 
    so.xtype = 'U' 
    AND 
    si.id = OBJECT_ID(so.name) 
GROUP BY 
    so.name 
ORDER BY 
    2 DESC

Если вам нужно, чтобы он был на 100% правильным, вы можете использовать недокументированную функцию sp_MSForEachTable

DECLARE @SQL VARCHAR(255) 
    SET @SQL = 'DBCC UPDATEUSAGE (' + DB_NAME() + ')' 
    EXEC(@SQL) 

    CREATE TABLE #foo 
    ( 
        tablename VARCHAR(255), 
        rc INT 
    ) 

    INSERT #foo 
        EXEC sp_msForEachTable 
            'SELECT PARSENAME(''?'', 1), 
            COUNT(*) FROM ?' 

    SELECT tablename, rc 
        FROM #foo 
        ORDER BY rc DESC 

    DROP TABLE #foo 
0 голосов
/ 04 февраля 2015
SELECT 
    O.ID,
    O.NAME,
    I.ROWCNT 
FROM SYSOBJECTS O 
INNER JOIN SYSINDEXES I 
ON O.ID = I.ID 
WHERE O.UID = 5 
    AND O.XTYPE = 'U' 
    AND I.STATUS = 0

Попробуйте использовать этот запрос, он даст вам идентификатор таблицы, имя таблицы и количество строк для этой таблицы.

UID = 5 означает, что я хочу проверить конкретную схему с id = 5.Вы можете проверить идентификатор схемы, используя SELECT SCHEMA_ID('<schema name>');

XTYPE = 'U' означает только пользовательские таблицы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...