是否有更好的方法来执行这样的查询:

SELECT COUNT(*) 
FROM (SELECT DISTINCT DocumentId, DocumentSessionId
      FROM DocumentOutputItems) AS internalQuery

我需要数一下这个表中不同项的数量,但不同项超过两列。

我的查询工作得很好,但我想知道我是否可以只使用一个查询(不使用子查询)得到最终结果


当前回答

您不喜欢现有查询的哪些方面?如果您担心两列之间的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>

edit

我进入了分析的死胡同,但答案很明显……

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
/

显然,所选择的分隔符必须是一个字符或一组字符,它不能出现在任何一列中。

其他回答

这对我很管用。在oracle中:

SELECT SUM(DECODE(COUNT(*),1,1,1))
FROM DocumentOutputItems GROUP BY DocumentId, DocumentSessionId;

在jpql:

SELECT SUM(CASE WHEN COUNT(i)=1 THEN 1 ELSE 1 END)
FROM DocumentOutputItems i GROUP BY i.DocumentId, i.DocumentSessionId;

编辑:从不太可靠的仅校验和查询更改 我发现了一种方法来做到这一点(在SQL Server 2005中),这对我来说很好,我可以使用尽可能多的列,因为我需要(通过将它们添加到CHECKSUM()函数)。REVERSE()函数将int类型转换为varchars类型,以使distinct类型更加可靠

SELECT COUNT(DISTINCT (CHECKSUM(DocumentId,DocumentSessionId)) + CHECKSUM(REVERSE(DocumentId),REVERSE(DocumentSessionId)) )
FROM DocumentOutPutItems

如果您使用的是固定长度的数据类型,则可以将其转换为二进制,从而非常容易和快速地完成此操作。假设documententid和DocumentSessionId都是int,因此都是4字节长…

SELECT COUNT(DISTINCT CAST(DocumentId as binary(4)) + CAST(DocumentSessionId as binary(4)))
FROM DocumentOutputItems

My specific problem required me to divide a SUM by the COUNT of the distinct combination of various foreign keys and a date field, grouping by another foreign key and occasionally filtering by certain values or keys. The table is very large, and using a sub-query dramatically increased the query time. And due to the complexity, statistics simply wasn't a viable option. The CHECKSUM solution was also far too slow in its conversion, particularly as a result of the various data types, and I couldn't risk its unreliability.

然而,使用上述解决方案几乎没有增加查询时间(与简单使用SUM相比),并且应该是完全可靠的!它应该能够帮助其他处于类似情况的人,所以我把它贴在这里。

我希望MS SQL也能做一些类似COUNT(DISTINCT A, B)的事情,但它不能。

起初,JayTee的答案对我来说似乎是一个解决方案,但经过一些测试,CHECKSUM()未能创建唯一的值。一个简单的例子是,CHECKSUM(31,467,519)和CHECKSUM(69,1120,823)给出的答案都是55。

然后我做了一些研究,发现微软不建议使用CHECKSUM进行更改检测。在一些论坛上,有人建议使用

SELECT COUNT(DISTINCT CHECKSUM(value1, value2, ..., valueN) + CHECKSUM(valueN, value(N-1), ..., value1))

但这也不令人欣慰。

您可以使用HASHBYTES()函数建议在TSQL校验和难题。然而,这也有一个小的机会不返回唯一的结果。

我建议使用

SELECT COUNT(DISTINCT CAST(DocumentId AS VARCHAR)+'-'+CAST(DocumentSessionId AS VARCHAR)) FROM DocumentOutputItems

希望这能起作用,我正在prima vista上写

SELECT COUNT(*) 
FROM DocumentOutputItems 
GROUP BY DocumentId, DocumentSessionId