2009-09-01 49 views
5

我需要一个查询来返回一个表,其中每列是另一个表的列中不同值的计数。SQL:计算每列中不同值的数量

我知道如何计算一列内不同的值:我想,我可能只是使这是一个很长的SELECT子句

select count(distinct columnA) from table1; 

select count(distinct columnA), count(distinct columnB), ... from table1; 

,但不是很优雅和硬编码。我更喜欢更灵活的东西。

+1

这是一个优雅和最简单的解决方案......你的意思是“给定一个表名,给出该表中每列的不同计数”? – gbn 2009-09-01 17:09:45

+1

您正在使用哪个数据库? – 2009-09-01 17:11:03

+0

可能的重复:http://stackoverflow.com/questions/1330692/distinct-pair-of-values-sql – 2009-09-01 17:12:48

回答

0

我感谢所有的答复。我认为在这种情况下最适合我的解决方案(从不知道表名的外部程序中计算表中每列的不同值的数量)如下:

运行“描述table1”并从结果中提取列名称。

循环遍历列名并创建查询来计算每列中的不同值。该查询看起来像“select count(distinct columnA),count(distinct columnB)... from table1”。

1

此代码应该为'table1'中的所有列提供每个列的相应不同值作为数据。

DECLARE @TableName VarChar (Max) = 'table1' 
DECLARE @SqlString VarChar (Max) 

set @SqlString = (
    SELECT DISTINCT 
    'SELECT ' + 
     RIGHT (ColumnList, LEN (ColumnList)-1) + 
     ' FROM ' + Table_Name 
    FROM INFORMATION_SCHEMA.COLUMNS COL1 
     CROSS AppLy (
     SELECT ', COUNT (DISTINCT [' + COLUMN_NAME + ']) AS ' + '''' + COLUMN_NAME + '''' 
      FROM INFORMATION_SCHEMA.COLUMNS COL2 
      WHERE COL1.TABLE_NAME = COL2.TABLE_NAME 
      FOR XML PATH ('') 
    ) TableColumns (ColumnList) 
    WHERE 
     1=1 AND 
     COL1.TABLE_NAME = @TableName 
) 

EXECUTE (@SqlString) 
1

,它的硬编码。

提供sql语句的字段列表并不是硬编码。这是常见和可接受的做法。

+0

...正如程序化地创建SQL,只要它(提供您的用户永远不会提供您输入的值 - 在这个问题中很好,你有列列表的地方)。 – ijw 2009-09-01 17:18:58

+0

如果我打算编写一些SQL代码,并且如果我在MSSqlServer上,我会检查sysobjects和syscolumns。 – 2009-09-01 17:23:45

+0

如果您想以更便携的方式编写代码,您应该从Information_Schema.Tables和Information_Schema中进行选择。列,而不是从sysobjects和syscolumns中选择 – Kibbee 2009-09-01 17:51:05

-3

DISTINCT是邪恶的。做COUNT/GROUP BY

+0

请通过更多信息对此进行限定。编写COUNT/GROUP BY时如何使用distinct evil? – Kibbee 2009-09-01 17:49:45

+0

DISTINCT对于较大的数据集以及从平台到平台的行为不正常。至少在我的经验。我发现分组结果更具可预测性,特别是如果您处理不同编码的数据,UTF等。 – 2009-09-01 17:55:24

+0

我将不得不使用group by。 – Ryan 2009-09-01 18:29:59

0

这对表中的每个字段都不一定是可能的。例如,除非将其转换为其他数据类型并失去一些精度,否则无法对SQL Server ntext或image字段执行DISTINCT。

+0

好点。我不应该担心这一点。这些字段只能是文本或数字。 – Ryan 2009-09-01 18:29:21

3

试试这个(SQL Server 2005中的语法):

DECLARE @YourTable table (col1 varchar(5) 
         ,col2 int 
         ,col3 datetime 
         ,col4 char(3) 
         ) 

insert into @YourTable values ('abcdf',123,'1/1/2009','aaa') 
insert into @YourTable values ('aaaaa',456,'1/2/2009','bbb') 
insert into @YourTable values ('bbbbb',789,'1/3/2009','aaa') 
insert into @YourTable values ('ccccc',789,'1/4/2009','bbb') 
insert into @YourTable values ('aaaaa',789,'1/5/2009','aaa') 
insert into @YourTable values ('abcdf',789,'1/6/2009','aaa') 


;with RankedYourTable AS 
(
SELECT 
    ROW_NUMBER() OVER(PARTITION by col1 order by col1) AS col1Rank 
     ,ROW_NUMBER() OVER(PARTITION by col2 order by col2) AS col2Rank 
     ,ROW_NUMBER() OVER(PARTITION by col3 order by col3) AS col3Rank 
     ,ROW_NUMBER() OVER(PARTITION by col4 order by col4) AS col4Rank 
    FROM @YourTable 
) 
SELECT 
    SUM(CASE WHEN  col1Rank=1 THEN 1 ELSE 0 END) AS col1DistinctCount 
     ,SUM(CASE WHEN col2Rank=1 THEN 1 ELSE 0 END) AS col2DistinctCount 
     ,SUM(CASE WHEN col3Rank=1 THEN 1 ELSE 0 END) AS col3DistinctCount 
     ,SUM(CASE WHEN col4Rank=1 THEN 1 ELSE 0 END) AS col4DistinctCount 
    FROM RankedYourTable 

OUTPUT:

col1DistinctCount col2DistinctCount col3DistinctCount col4DistinctCount 
----------------- ----------------- ----------------- ----------------- 
4     3     6     2 

(1 row(s) affected) 
+0

+1:简洁,优雅,厚脸皮... – gbn 2009-09-01 18:35:24