计算一个查询中多个表的行数

时间:2010-11-15 08:30:30

标签: sql sql-server tsql

我有一个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 个答案:

答案 0 :(得分:4)

您可以使用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中删除。

第二个问题是,拥有动态架构通常表示建模中出现了其他问题 - 可能是属性拆分(即1月和2月的销售给出不同的表,即使它们是“在逻辑上是相同的,应该出现在同一个表中,可能还有一个额外的列来区分它们”


当然,您希望根据特定的clientID进行过滤,因此查询更像是:

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

(假设@OwnerID是所有者寻求的,并且是一个int)

答案 1 :(得分:1)

这将从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 

答案 2 :(得分:1)

您可以使用:

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

答案 3 :(得分:0)

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

尝试使用此查询,它将为您提供该表的id,表名和该表的行数。

UID = 5 表示我想检查ID = 5的特定架构。您可以使用SELECT SCHEMA_ID('<schema name>');检查架构ID

XTYPE ='U'表示仅限用户定义的表。