Count()在SQL中没有按预期工作

时间:2016-04-30 14:36:25

标签: sql count sql-server-2014

一位同事为我准备了一张我需要映射数据的表,而表包含两个字段OP_ID和BillType。理论上,两者之间应该存在一对一的对应关系:每个Op_ID应该只有一种账单类型。

然而,当我开始使用它时,我注意到有不同BillTypes的重复OP_ID。 E.g:

OP_Id               BillType 
007a000v9GWkAAM BillReady 
007a000v9GWkAAM RateReady

首先,我构建了一个查询,将数据分组为ID和BillTypes的唯一组合:

SELECT OP_ID, BillType
FROM MappingTable
GROUP BY OP_ID, BillType

足够简单。该集应该并且确实包括上述两个记录。然后,我围绕此包装另一个查询来计算聚合数据集中的OP_Ids。从理论上讲,任何具有多个BillType的OP_ID都应该出现两次,因此它应该返回一个>对吧?

SELECT OP_ID, BillType, Count(OP_ID)
FROM 
    (
    SELECT OP_ID, BillType
    FROM MappingTable
    GROUP BY OP_ID, BillType
    ) Base
GROUP BY  OP_ID, BillType
HAVING Count(OP_ID) > 1

但是这个查询什么都不返回。更令人费解的是:当我删除HAVING子句并将查询限制为仅提取上述OP_ID时,因为我已经知道它是一个骗局,我得到的是:

OP_ID          BillType  CountOfOP_IDs
007a000v9GWkAAM BillReady   1
007a000v9GWkAAM RateReady   1

因此OP_ID 007a000v9GWkAAM显然有两条记录,但SQL只计算一条!

这看起来很简单,我确信我只是缺少一些关于COUNT()如何工作的基本知识。作为参考,我正在研究SQL Server 2014,两列都是nvarchar。我还确认SQL将两个记录中的OP_ID评估为相同。任何人都知道为什么会这样吗?

4 个答案:

答案 0 :(得分:4)

Count计算已分组为一行的行数。只需从外部组删除帐单类型。

另请参阅count distinct选项。这可能会更容易。

答案 1 :(得分:3)

声明

SELECT OP_ID, BillType
FROM MappingTable
GROUP BY OP_ID, BillType

是很长的路要走

SELECT DISTINCT OP_ID, BillType
FROM MappingTable

如果您现在拥有OP_IDBillType的不同组合,则在这两个字段上添加新的GROUP BY将无效。

SELECT ...
FROM ( SELECT DISTINCT OP_ID, BillType
       FROM MappingTable
     ) Base
GROUP BY  OP_ID, BillType
HAVING Count(OP_ID) > 1

新的“群组”将全部由内部SELECT的一行组成,因此COUNT将始终为1,这意味着Count(OP_ID) > 1始终为false,您将不会返回任何内容

也许您打算查找具有多个OP_Id值的BillType值。如果是这样,您应该从BillType中删除GROUP BYsuggested by @DonKirkby

如果您对此感兴趣,那么您可以通过检索第一个和最后一个BillType值来获得结果中BillType个值的两个示例(通常情况下很好)研究,至少)。

SELECT OP_ID, COUNT(*), MIN(BillType), MAX(BillType)
FROM ( SELECT DISTINCT OP_ID, BillType
       FROM MappingTable
     ) Base
GROUP BY OP_ID
HAVING COUNT(*) > 1

您可以使用COUNT(DISTINCT ...)缩短整个语句,也可以suggested by @DonKirkby缩短整个语句。

SELECT OP_ID, COUNT(DISTINCT BillType), MIN(BillType), MAX(BillType)
FROM MappingTable
GROUP BY OP_ID
HAVING COUNT(DISTINCT BillType) > 1

答案 2 :(得分:1)

你的方法很有意义。我的猜测是OP_ID值略有不同 - 可能是由于编码问题或角色外观相似。

这很容易找到。这个查询返回了什么?

select mt.*
from mappingtable
where op_id = '007a000v9GWkAAM';

顺便提一下,您可以将查询简化为:

SELECT OP_ID
FROM MappingTable
GROUP BY OP_ID
HAVING MIN(BillType) <> MAX(BillType);

如果您想查看BillType值,请将GROUP_CONCAT(BillType)添加到SELECT

编辑:

以上内容都是正确的,但您的查询不起作用,因为外部查询按OP_IDBILL_TYPE进行分组。试试这个版本:

SELECT OP_ID, Count(OP_ID)
FROM (SELECT OP_ID, BillType
      FROM MappingTable
      GROUP BY OP_ID, BillType
      ) Base
GROUP BY OP_ID
HAVING Count(OP_ID) > 1;

您没有返回任何行,因为您要对相同的键进行两次分组。子查询删除重复项,因此外部的计数始终为1。

答案 3 :(得分:1)

SELECT * 
FROM MappingTable 
WHERE OP_ID in (SELECT OP_ID 
                FROM (SELECT OP_ID, count(*) ct
                      FROM MappingTable
                      GROUP BY OP_ID)
                WHERE ct > 1)

对于BOTH列,没有(至少在您的示例中)重复,只是OP_ID的意外重复。