有没有更好的方法来执行这样的查询:
SELECT COUNT(*)
FROM (SELECT DISTINCT DocumentId, DocumentSessionId
FROM DocumentOutputItems) AS internalQuery
我需要计算该表中不同项目的数量,但是不同项目超过两列。
我的查询工作正常,但我想知道是否可以仅使用一个查询(而不使用子查询)获得最终结果
有没有更好的方法来执行这样的查询:
SELECT COUNT(*)
FROM (SELECT DISTINCT DocumentId, DocumentSessionId
FROM DocumentOutputItems) AS internalQuery
我需要计算该表中不同项目的数量,但是不同项目超过两列。
我的查询工作正常,但我想知道是否可以仅使用一个查询(而不使用子查询)获得最终结果
Answers:
如果要提高性能,则可以尝试在两个列的哈希值或串联值上创建一个持久化的计算列。
一旦保留,只要该列是确定性的并且您正在使用“合理的”数据库设置,就可以对其进行索引和/或在其上创建统计信息。
我相信计算列的独特计数将等同于您的查询。
编辑:从不太可靠的仅校验和查询中更改, 我发现了一种执行此操作的方法(在SQL Server 2005中)对我来说很好,并且我可以根据需要使用任意多的列(通过将它们添加到CHECKSUM()函数)。REVERSE()函数将int转换为varchars,以使其更加可靠
SELECT COUNT(DISTINCT (CHECKSUM(DocumentId,DocumentSessionId)) + CHECKSUM(REVERSE(DocumentId),REVERSE(DocumentSessionId)) )
FROM DocumentOutPutItems
您不喜欢的现有查询有什么用?如果您担心DISTINCT
跨两列不仅仅返回唯一的排列,为什么不尝试呢?
它当然可以按照您在Oracle中的预期工作。
SQL> select distinct deptno, job from emp
2 order by deptno, job
3 /
DEPTNO JOB
---------- ---------
10 CLERK
10 MANAGER
10 PRESIDENT
20 ANALYST
20 CLERK
20 MANAGER
30 CLERK
30 MANAGER
30 SALESMAN
9 rows selected.
SQL> select count(*) from (
2 select distinct deptno, job from emp
3 )
4 /
COUNT(*)
----------
9
SQL>
编辑
我走进了分析的盲区,但答案却显而易见。
SQL> select count(distinct concat(deptno,job)) from emp
2 /
COUNT(DISTINCTCONCAT(DEPTNO,JOB))
---------------------------------
9
SQL>
编辑2
给定以下数据,以上提供的串联解决方案将计算错误:
col1 col2
---- ----
A AA
AA A
所以我们包括一个分隔符...
select col1 + '*' + col2 from t23
/
显然,所选的分隔符必须是一个字符或一组字符,不能出现在任何一列中。
要作为单个查询运行,请串联各列,然后获取串联字符串实例的不同计数。
SELECT count(DISTINCT concat(DocumentId, DocumentSessionId)) FROM DocumentOutputItems;
在MySQL中,您可以执行没有连接步骤的相同操作,如下所示:
SELECT count(DISTINCT DocumentId, DocumentSessionId) FROM DocumentOutputItems;
MySQL文档中提到了此功能:
http://dev.mysql.com/doc/refman/5.7/zh-CN/group-by-functions.html#function_count-distinct
SELECT COUNT(DISTINCT (DocumentId, DocumentSessionId)) FROM DocumentOutputItems;
怎么样:
选择计数(*) 从 (选择计数(*)cnt 来自DocumentOutputItems 按DocumentId,DocumentSessionId分组)t1
可能只是和您已经做的一样,但是避免了DISTINCT。
GROUP BY
可能会给查询转换带来一些其他挑战,以实现所需的输出(例如,当原始查询已经具有GROUP BY
或HAVING
子句...时)
这是没有子选择的较短版本:
SELECT COUNT(DISTINCT DocumentId, DocumentSessionId) FROM DocumentOutputItems
它在MySQL中运行良好,我认为优化器可以更轻松地了解这一点。
编辑:显然我误读了MSSQL和MySQL-对此感到抱歉,但是无论如何它还是有帮助的。
count ( distinct CHECKSUM ([Field1], [Field2])
许多(大多数?)SQL数据库可以使用类似值的元组,因此您可以这样做:
SELECT COUNT(DISTINCT (DocumentId, DocumentSessionId))
FROM DocumentOutputItems;
如果数据库不支持此功能,则可以按照@ oncel-umut-turer建议的CHECKSUM或其他标量函数进行模拟,以提供良好的唯一性例如
COUNT(DISTINCT CONCAT(DocumentId, ':', DocumentSessionId))
。
元组的相关用法正在执行IN
查询,例如:
SELECT * FROM DocumentOutputItems
WHERE (DocumentId, DocumentSessionId) in (('a', '1'), ('b', '2'));
select count(distinct(a, b))
?:D
我已经使用了这种方法,并且对我有用。
SELECT COUNT(DISTINCT DocumentID || DocumentSessionId)
FROM DocumentOutputItems
就我而言,它提供了正确的结果。
如果只有一个字段要“ DISTINCT”,则可以使用:
SELECT COUNT(DISTINCT DocumentId)
FROM DocumentOutputItems
并返回与原始查询计划相同的查询计划,这是在SET SHOWPLAN_ALL ON的测试下得出的。但是,您正在使用两个字段,因此可以尝试一些疯狂的操作:
SELECT COUNT(DISTINCT convert(varchar(15),DocumentId)+'|~|'+convert(varchar(15), DocumentSessionId))
FROM DocumentOutputItems
但是如果涉及NULL,就会遇到问题。我只会坚持使用原始查询。
我用Google搜索自己的问题时发现了这一点,发现如果您计算DISTINCT对象,则会得到正确的返回值(我使用的是MySQL)
SELECT COUNT(DISTINCT DocumentID) AS Count1,
COUNT(DISTINCT DocumentSessionId) AS Count2
FROM DocumentOutputItems
DocumentId
和DocumentSessionId
)。如果OP使用的是MySQL而不是MS SQL Server,则AlexanderKjäll已经发布了正确的答案。
我希望MS SQL也可以做类似COUNT(DISTINCT A,B)的操作。但是不能。
最初,JayTee的答案似乎对我来说是一个解决方案,因为一些测试CHECKSUM()无法创建唯一值。一个简单的例子是,CHECKSUM(31,467,519)和CHECKSUM(69,1120,823)给出的答案都是55。
然后,我进行了一些研究,发现Microsoft不建议将CHECKSUM用于更改检测目的。在某些论坛中,建议使用
SELECT COUNT(DISTINCT CHECKSUM(value1, value2, ..., valueN) + CHECKSUM(valueN, value(N-1), ..., value1))
但这也不令人安心。
您可以按照TSQL CHECKSUM conundrum中的建议使用HASHBYTES()函数。但是,这也极有可能不会返回唯一的结果。
我建议使用
SELECT COUNT(DISTINCT CAST(DocumentId AS VARCHAR)+'-'+CAST(DocumentSessionId AS VARCHAR)) FROM DocumentOutputItems
这个怎么样,
Select DocumentId, DocumentSessionId, count(*) as c
from DocumentOutputItems
group by DocumentId, DocumentSessionId;
这将使我们获得所有可能的DocumentId和DocumentSessionId组合的计数
我有一个类似的问题,但是我的查询是一个子查询,主查询中有比较数据。就像是:
Select code, id, title, name
(select count(distinct col1) from mytable where code = a.code and length(title) >0)
from mytable a
group by code, id, title, name
--needs distinct over col2 as well as col1
忽略了它的复杂性,我意识到我无法通过原始问题中描述的double子查询将a.code的值输入到子查询中
Select count(1) from (select distinct col1, col2 from mytable where code = a.code...)
--this doesn't work because the sub-query doesn't know what "a" is
因此,最终我发现我可以作弊,并合并以下各列:
Select count(distinct(col1 || col2)) from mytable where code = a.code...
这就是最终的工作
如果您使用固定长度的数据类型,则可以强制转换binary
为轻松,快速地执行此操作。假设DocumentId
和DocumentSessionId
均为int
s,因此为4个字节长...
SELECT COUNT(DISTINCT CAST(DocumentId as binary(4)) + CAST(DocumentSessionId as binary(4)))
FROM DocumentOutputItems
我的特定问题要求我将各种外键和日期字段的不同组合除以a SUM
,COUNT
再按另一个外键分组,并偶尔按某些值或键进行过滤。该表非常大,使用子查询会大大增加查询时间。而且由于复杂性,统计信息根本不是一个可行的选择。的CHECKSUM
解决方案的转换也太慢了,特别是由于各种数据类型的影响,我不能冒险说它的不可靠性。
但是,使用上述解决方案实际上并没有增加查询时间(与仅使用相比SUM
),并且应该是完全可靠的!它应该能够在类似情况下帮助其他人,所以我在这里发布。