从组中获取最大计数

时间:2013-07-18 06:13:04

标签: sql group-by max

我无法在sql中获取组函数的输出.Below是表

的详细信息

我有1个表格表名称“check”有2列pid,cid

 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 PID                                                VARCHAR2(20)
 CID                                                VARCHAR2(20)

以下是可用的行

select * from checks;

PID                  CID
-------------------- --------------------
p1                   c1
p1                   c1
p1                   c2
p1                   c2
p1                   c2
p2                   c1
p2                   c1
p2                   c1
p2                   c1
p2                   c1
p2                   c1
p2                   c2
p2                   c2
p2                   c2
p2                   c2
p2                   c2

P表示参与者,c表示类别

问题

我需要知道哪个参与者参与哪个类别参与者参与的次数最多。(每个参与者)

预期结果:

pid   cid    count(cid)
---   ---    -----------
p1    c2         3
p2    c1         6

5 个答案:

答案 0 :(得分:4)

假设有一个支持窗口函数和CTE的数据库系统(你没有指定一个,但我怀疑是Oracle?),我写道:

;With Groups as (
    select pid,cid,COUNT(*) as cnt from checks group by pid,cid
), Ordered as (
    select pid,cid,cnt,
       ROW_NUMBER() OVER (PARTITION BY pid ORDER BY cnt desc) as rn,
       COUNT(*) OVER (PARTITION BY pid) as multi
    from Groups
)
select pid,cid,cnt
from Ordered
where rn = 1 and multi > 1

第一个CTE(Groups)只查找每个唯一cid,pid组合的计数。第二个CTE(Ordered)根据计数为这些结果分配行号 - 最高计数分配行数1.我们还计算每个pid生成的总行数。

最后,我们选择那些分配了行号1(最高计数)的行,并为此我们获得了同一pid的多个结果。

这是一个Oracle fiddle。这是一个SQL Server version(感谢Andriy M制作Oracle的一个)

答案 1 :(得分:1)

这将为您提供一些基本想法:

enter image description here

结果如下所示。此外,由于p1参与了多个类别,因此当我们使用时,p1将与不同行中的每个新类别一起出现:'group by PID,CID'

enter image description here

答案 2 :(得分:1)

一步一步:

首先,获取每(PID, CID)行的计数。这很简单:

SELECT
  PID,
  CID,
  COUNT(*) AS cnt
FROM checks
GROUP BY
  PID,
  CID

您可以为您的示例获得此结果集:

PID  CID  cnt
---  ---  ---
p1   c1   2
p1   c2   3
p2   c1   6
p2   c2   5

现在,请输入COUNT(*) OVER (PARTITION BY PID)以返回每人的类别数量:

SELECT
  PID,
  CID,
  COUNT(*) AS cnt,
  COUNT(*) OVER (PARTITION BY PID) AS cat_cnt
FROM checks
GROUP BY
  PID,
  CID

OVER子句将“正常”聚合函数COUNT()转换为 window 聚合函数。这使得COUNT(*)分组行集而非源代码集上运行。因此,在这种情况下,COUNT(*) OVER ...计算每PID行,这对我们来说具有每人类别计数的含义。这是更新的结果集:

PID  CID  cnt  cnt_cat
---  ---  ---  -------
p1   c1   2    2
p1   c2   3    2
p2   c1   6    2
p2   c2   5    2

还剩下的一件事就是按cntPID个值进行排名。这可能很棘手,因为最重要的可能存在联系。如果你总是想要每行PID一行,并且对于CID, cnt在出现平局时完全无动于衷,你可以像这样修改查询:

SELECT
  PID,
  CID,
  COUNT(*) AS cnt,
  COUNT(*) OVER (PARTITION BY PID) AS cat_cnt,
  ROW_NUMBER() OVER (PARTITION BY PID ORDER BY COUNT(*) DESC) AS rn
FROM checks
GROUP BY
  PID,
  CID

这就是结果集的样子:

PID  CID  cnt  cnt_cat  rn
---  ---  ---  -------  --
p1   c1   2    2        2
p1   c2   3    2        1
p2   c1   6    2        1
p2   c2   5    2        2

此时,结果包含生成最终输出所需的所有数据,您只需要在cnt_catrn上进行过滤。但是,你不能直接这样做。相反,将最后一个查询用作派生表,无论是WITH表表达式还是“普通”子选择。以下是使用WITH的示例:

WITH grouped AS (
  SELECT
    PID,
    CID,
    COUNT(*) AS cnt,
    COUNT(*) OVER (PARTITION BY PID) AS cat_cnt,
    ROW_NUMBER() OVER (PARTITION BY PID ORDER BY COUNT(*) DESC) AS rn
  FROM checks
  GROUP BY
    PID,
    CID
)
SELECT PID, CID, cnt
FROM grouped
WHERE cat_cnt > 1
  AND rn = 1
;

这是一个SQL小提琴演示(使用Oracle):http://sqlfiddle.com/#!4/cd62d/8

要在排名部分进一步扩展,如果您仍希望每CID, cnt返回一个PID,但希望更多地控制哪一行应被视为“赢家” ,你需要在排名函数的ORDER BY子句中添加一个打破平局。例如,您可以修改原始表达式

ROW_NUMBER() OVER (PARTITION BY PID ORDER BY COUNT(*) DESC) AS rn

这一个:

ROW_NUMBER() OVER (PARTITION BY PID ORDER BY COUNT(*) DESC, CID) AS rn

即。决斗者是CID,两个或多个CID的最高统计者,在其他人胜出之前排序。

但是,您可能希望决定每个PID返回所有最高计数。在这种情况下,请使用RANK()DENSE_RANK()代替ROW_NUMBER()(并且不要打破平局),例如:

RANK() OVER (PARTITION BY PID ORDER BY COUNT(*) DESC) AS rn

答案 3 :(得分:-1)

select pid, cid, count
from (
    select pid, cid, count(*) as count
    from checks
    group by pid, cid
    order by count DESC
) as temp
group by pid;

同样适用于MySQL。

答案 4 :(得分:-1)

这是MySQL解决方案:

SELECT tbl1.pid, tbl1.cid, tbl1.pairCount

FROM        (   SELECT checks.pid, checks.cid, COUNT(*) AS pairCount
                FROM checks
                GROUP BY checks.pid, checks.cid ) AS tbl1

            INNER JOIN 

            (   SELECT checks.pid, checks.cid, COUNT(*) AS pairCount
                FROM checks 
                GROUP BY checks.pid, checks.cid ) AS tbl2   

            ON tbl1.pid=tbl2.pid AND tbl1.cnt > tbl2.cnt

抱歉,我正在使用2个子查询,但无法找到更好的内容。至少,它有效。 Fiddle

我不能简单地使用GROUP BY,因为当使用为非分组列返回的GROUP BY值是任意的时,不是来自发生MAX()值的同一行:MYSQL shows incorrect rows when using GROUP BY