如何为数据库中的所有表返回变量的不同计数?

时间:2018-10-03 19:27:14

标签: sql sql-server

我有一个包含60多个表的SQL数据库,几乎所有表都填充有CLIENTID字段。我想计算每个表中唯一客户端ID的数量。

我正在寻找的结果是:

TABLE_NAME; CLIENTID_COUNT
dbo.HISTORY; 650
dbo.VISITS; 596
dbo.SALES; 1053
...; ...

这似乎应该很简单,但是我已经游玩了几个小时,无法弄清楚这个。请帮忙!

5 个答案:

答案 0 :(得分:1)

IF OBJECT_ID('tempdb..#temp_RESULTS') IS NOT NULL DROP TABLE #temp_RESULTS
CREATE TABLE #TEMP_RESULTS
(
TABLENAME VARCHAR(MAX),
CLIENTCNT BIGINT
)

DECLARE @TABLENAME VARCHAR(MAX)
DECLARE @command VARCHAR(MAX)

IF OBJECT_ID('tempdb..#temp_PROCESS') IS NOT NULL DROP TABLE #temp_PROCESS
SELECT * INTO #TEMP_PROCESS FROM sys.tables 

WHILE EXISTS(SELECT * FROM [#TEMP_PROCESS])
BEGIN
SET @TABLENAME = (SELECT TOP 1 [NAME] FROM [#TEMP_PROCESS])
SET @command = ('SELECT ''' + @TABLENAME + ''', COUNT(DISTINCT CLIENTID) AS CLIENTCNT FROM ' + @TABLENAME)
SELECT @command
INSERT INTO #TEMP_RESULTS
EXEC(@command) 

DELETE FROM [#TEMP_PROCESS] WHERE [NAME] = @TABLENAME
END

SELECT * FROM [#TEMP_RESULTS]

答案 1 :(得分:1)

假设该列在每个表中都完全是ClientId,那么您应该可以按原样使用它:

DROP TABLE IF EXISTS #clientId
CREATE TABLE #clientId
(
    TableName nvarchar(1000),
    ClientIdCount bigint
)

DECLARE @TableName nvarchar(1000);
DECLARE @CurrentQuery nvarchar(2000);

DECLARE result_cursor CURSOR local fast_forward FOR
SELECT DISTINCT
    '['+TABLE_SCHEMA + '].[' + TABLE_NAME + ']'
FROM
    INFORMATION_SCHEMA.COLUMNS
WHERE
    COLUMN_NAME = 'ClientId'

OPEN result_cursor
FETCH NEXT FROM result_cursor into @TableName
WHILE @@FETCH_STATUS = 0
BEGIN 

SET @CurrentQuery = 'SELECT ''' + @TableName + ''', COUNT(DISTINCT ClientId) FROM ' + @TableName
--print @CurrentQuery

INSERT INTO
    #clientId
(
    TableName,
    ClientIdCount
)
EXEC(@CurrentQuery)

FETCH NEXT FROM result_cursor into @TableName
END
--end loop

--clean up
CLOSE result_cursor
DEALLOCATE result_cursor

GO

SELECT
    *
FROM
    #clientId

答案 2 :(得分:1)

您可以使用动态sql。

这将通读您的系统表,查找具有ClientID列的系统表,并从每个表中构建一般形状为“ Select Count(DISTINCT ClientID)”的查询文本。

DECLARE @SQLQuery as nvarchar(max) = ''

------------------------------------
-- GET THE TABLES THAT HAVE A CLIENTID FROM SCHEMA
SELECT @SQLQuery = @SQLQuery + qryTxt FROM (
    SELECT DISTINCT 'SELECT ''' + tables.name + ''', COUNT(DISTINCT CLIENTID) FROM ' + tables.name + ' UNION ' AS qryTxt
    FROM sys.columns left join sys.tables on columns.object_id = tables.object_id where columns.name = CLIENTID AND isnull(tables.name, '') <> '') subquery

------------------------------------
-- REMOVE THE LAST 'UNION' KEYWORD FROM SQLQUERY 
SET @SQLQuery = left(@sqlQuery, len(@sqlQuery) - 5)

------------------------------------
-- EXECUTE
execute sp_executesql @SQLQuery

答案 3 :(得分:1)

我真的不喜欢游标和循环。即使从性能的角度来看并不会有太大的不同,我还是想分享一下如何利用系统表和动态sql来避免使用游标,而在循环或临时表中使用这种方法。

此代码实际上就是您要做的所有事情。

declare @SQL nvarchar(max) = ''

select @SQL = @SQL + 'select TableName = ''' + t.name + ''', ClientID_Count = count(distinct clientID)
from ' + QUOTENAME(t.name) + ' UNION ALL ' 
from sys.tables t
join sys.columns c on c.object_id = t.object_id
where c.name = 'clientID'

select @SQL = left(@SQL, len(@SQL) - 10) --removes the last UNION ALL

select @SQL
--once your comfortable the dynamic sql is correct just uncomment the line below.
--exec sp_executesql @SQL

答案 4 :(得分:0)

与其他答案类似的模式,但这就是我要解决的方法:

IF OBJECT_ID('#Tables', 'U') IS NOT NULL
    DROP TABLE #Tables;
SELECT ID = IDENTITY(INT, 1, 1),
    SchemaName = OBJECT_SCHEMA_NAME([object_id]),
    TableName = OBJECT_NAME([object_id]),
    ColumnName = name,
    DistinctCount = 0
    INTO #Tables
    FROM sys.columns
    WHERE name = 'CLIENTID';

DECLARE @ID INT = 1,
    @MaxID INT = (SELECT MAX(ID) FROM #Tables);
WHILE @ID < @MaxID
BEGIN;
    DECLARE @SQLCommand VARCHAR(MAX);
    SELECT @SQLCommand = FORMATMESSAGE('
UPDATE #Tables SET DistinctCount = (
    SELECT COUNT(DISTINCT %s) FROM %s.%s
    )
    WHERE ID = %i;',
        QUOTENAME(ColumnName), QUOTENAME(SchemaName), QUOTENAME(TableName), ID)
        FROM #Tables
        WHERE ID = @ID;
    EXEC (@SQLCommand);
    SET @ID += 1;
END;

SELECT *
    FROM #Tables;