与行号计数相关的子查询

Posted

技术标签:

【中文标题】与行号计数相关的子查询【英文标题】:Correlated subquery with row number count 【发布时间】:2020-08-07 19:25:57 【问题描述】:

我有一个如下表,我想要的是使用每个 uid 组的 id 最少的初始行。

表格如下

_id  uid  type 
1     a    a
2     b    bbb   #satisfied
3     b    ccc
4     b    aaa   #satisfied
5     a    aaa   #satisfied
6     b    eee

我已经可以使用以下相关子查询获取初始行

SELECT *
FROM table
WHERE _id IN (
               SELECT MIN(_id) 
               FROM table 
               WHERE type IN ('aaa','bbb')
               GROUP BY uid
             );

但是,我希望第 4 列显示满足条件 (type IN ('aaa','bbb')) 的行数,如下所示 cnt

_id  uid  type  cnt
5     a    aaa   1
2     b    bbb   2

我想我可以计算这个使用几个连接,然后将结果连接到我的代码中......但这很丑......有没有什么优雅的方法来实现这个......

【问题讨论】:

【参考方案1】:

你可以试试这个:

SELECT t1.*, t2.cnt
FROM table t1 INNER JOIN (
  SELECT MIN(_id) AS id, COUNT(_id) AS cnt
  FROM table 
  WHERE type IN ('aaa','bbb')
  GROUP BY uid
) t2 ON t1._id = t2.id
ORDER BY t1.uid

【讨论】:

【参考方案2】:

如果您运行的是 mysql 8.0,则可以为此使用窗口函数:

select _id, uid, type, cnt
from (
    select 
        t.*, 
        count(*) over(partition by uid) cnt,
        row_number() over(partition by uid order by _id) rn
    from mytable t
    where type in ('aaa', 'bbb')
) t
where rn = 1

【讨论】:

【参考方案3】:

您可以在没有子查询的情况下执行此操作。在 MySQL 8+ 中,你可以使用这个逻辑:

SELECT DISTINCT MIN(_id) OVER (PARTITION BY uid) as _id,
       uid,
       FIRST_VALUE(type) OVER (PARTITION BY uid ORDER BY _id) as type,
       COUNT(*) OVER (PARTITION BY uid) as cnt
FROM table 
WHERE type IN ('aaa', 'bbb');

不幸的是,MySQL 没有“第一”聚合函数,但如果你喜欢的话,有一个技巧:

SELECT MIN(_id) as _id, uid,
       SUBSTRING_INDEX(GROUP_CONCAT(type ORDER BY _id), ',', 1) as type,
       COUNT(*) as cnt
FROM table 
WHERE type IN ('aaa', 'bbb')
GROUP BY uid;

【讨论】:

以上是关于与行号计数相关的子查询的主要内容,如果未能解决你的问题,请参考以下文章

不是正确的子查询,一个州的多个县试图获得州的计数

Django:如何从与用户相关的子查询集中获取不同的父列表?

Oracle 优化——奇怪的执行计划左加入一个不相关的子查询

symfony 中的子查询

Mysql的子查询相关知识,少但是精

SQL相关子查询与非相关子查询