Transact-Sql Count Distinct操作计算列中的所有非空值。我需要计算一组表中每列的不同值的数量,包括空值(因此,如果列中有空值,则结果应为(Select Count(Distinct COLNAME) From TABLE) + 1
。
这将在DB中每个表的每一列上重复。包括数百个表,其中一些表有超过1M行。因为这需要在每一列上完成,所以为每列添加索引不是一个好的选择。
这将作为ASP.net站点的一部分完成,因此与代码逻辑的集成也可以(即:这不必作为一个查询的一部分完成,但如果可以以良好的性能完成,然后更好)。
最有效的方法是什么?
我从一个好的代表性表格上给出的答案中测试了不同的方法。该表有320万条记录,数十列(少数有索引,大多数没有)。一列有320万个唯一值。其他列的范围从所有Null(一个值)到最多40K唯一值。对于每种方法,我进行了四次测试(每次尝试多次,平均结果):一次20列,一次5列,1列有很多值(3.2M),1列有少量值( 167)。以下是最快到最慢的结果
测试结果(以秒为单位):
Method 20_Columns 5_Columns 1_Column (Large) 1_Column (Small)
1) Count/GroupBy 10.8 4.8 2.8 0.14
2) CountDistinct 12.4 4.8 3 0.7
3) dense_rank 226 30 6 4.33
4) Count+Max 98.5 44 16 12.5
注意:
Count
。感谢您的帮助和建议!
答案 0 :(得分:9)
SELECT COUNT(*)
FROM (SELECT ColumnName
FROM TableName
GROUP BY ColumnName) AS s;
GROUP BY
选择包含NULL的不同值。 COUNT(*)
将包含NULL,而COUNT(ColumnName)
则忽略NULL。
答案 1 :(得分:7)
我认为您应该尝试保持表扫描的数量并一次计算一个表中的所有列。这样的事情值得尝试。
;with C as
(
select dense_rank() over(order by Col1) as dnCol1,
dense_rank() over(order by Col2) as dnCol2
from YourTable
)
select max(dnCol1) as CountCol1,
max(dnCol2) as CountCol2
from C
测试查询
答案 2 :(得分:3)
开发OP自己的解决方案:
SELECT
COUNT(DISTINCT acolumn) + MAX(CASE WHEN acolumn IS NULL THEN 1 ELSE 0 END)
FROM atable
答案 3 :(得分:2)
运行一个查询计算Distinct值的数量,如果列中有任何NULL,则添加1(使用子查询)
Select Count(Distinct COLUMNNAME) +
Case When Exists
(Select * from TABLENAME Where COLUMNNAME is Null)
Then 1 Else 0 End
From TABLENAME
答案 4 :(得分:2)
您可以尝试:
count(
distinct coalesce(
your_table.column_1, your_table.column_2
-- cast them if you want replace value from column are not same type
)
) as COUNT_TEST
函数coalesce可帮助您将两列组合为replace not null值。
我在我的情况下使用了这个,并且正确地得到了成功。
答案 5 :(得分:0)
不确定这是最快的,但可能值得测试。用例赋予null一个值。显然,您需要选择一个不会在实际数据中出现的null值。根据查询计划,这将是Cheran S提出的计数(*)(分组)解决方案的死热。
SELECT
COUNT( distinct
(case when [testNull] is null then 'dbNullValue' else [testNull] end)
)
FROM [test].[dbo].[testNullVal]
使用此方法也可以计算多个列
SELECT
COUNT( distinct
(case when [testNull1] is null then 'dbNullValue' else [testNull1] end)
),
COUNT( distinct
(case when [testNull2] is null then 'dbNullValue' else [testNull2] end)
)
FROM [test].[dbo].[testNullVal]