我有一个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;
答案 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'表示仅限用户定义的表。