Коррелированный подзапрос с количеством строк - PullRequest
0 голосов
/ 24 апреля 2020

У меня есть следующая таблица, и я хочу получить начальную строку с наименьшим идентификатором каждой группы uid.

Таблица выглядит следующим образом

_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

Я думаю, что могу сосчитать это, используя несколько соединений, а затем присоединить результат к моему коду ... Но это ужасно ... Есть ли какой-нибудь элегантный способ добиться этого ...

Ответы [ 3 ]

1 голос
/ 24 апреля 2020

Если вы используете 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
1 голос
/ 24 апреля 2020

Вы можете сделать это без подзапроса. В MySQL 8+ вы можете использовать эту логику c:

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;
1 голос
/ 24 апреля 2020

Вы можете попробовать это:

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
...