Запрос MySQL для поиска уникальных записей

#mysql #sql

#mysql #sql

Вопрос:

У меня есть следующая таблица:

  ---- ------- --------- 
| id | media | status  |
 ---- ------- --------- 
|  1 | FOO   | ACTIVE  |
|  1 | FOO   | PENDING |
| >1 | BAR   | ACTIVE  |
|  2 | FOO   | ACTIVE  |
|  2 | FOO   | PENDING |
| >3 | BAR   | ACTIVE  |
 ---- ------- --------- 
  

Что мне нужно получить, так это список id , в котором есть ACTIVE записи с определенным media значением, но нет PENDING записи с таким же media значением. В моем примере id=1 покрыли FOO , но не раскрыли BAR .

Таким образом, результирующая таблица должна быть:

  ---- 
| id |
 ---- 
|  1 |
|  3 |
 ---- 
  

Единственное решение, которое я вижу, — создать две таблицы с ACTIVE и PENDING записями отдельно, затем найти записи, которые есть только в ACTIVE , а не в PENDING нет. Но я понятия не имею, как построить запрос.

Пожалуйста, сообщите.

Комментарии:

1. Если идентификатор имеет два типа носителей, один с ожиданием, другой без, должен ли он все еще быть включен?

2. О, мои извинения. Если id имеет только ожидание media , то оно не включено.

3. Я спрашиваю о том, где у одного идентификатора есть два разных типа носителей, и у одного есть ожидание, а другой только активен. Смотрите мой ответ о практической разнице.

Ответ №1:

Я бы сделал это с помощью group by и having , потому что это очень гибкий способ формулирования запросов такого типа:

 select id
from table t
group by id, media
having sum(status = 'ACTIVE') > 0 and
       sum(status = 'PENDING') = 0;
  

Комментарии:

1. что, если OP имеет более 2 статусов?? например, активный, ожидающий, с истекшим сроком действия, удержание?

2. @timus2001 . . . Это будет работать так, как написано. Кроме того, легко добавить дополнительные правила, такие как не более одного просроченного и трех удерживаемых.

Ответ №2:

Использование соединения по ЛЕВОМУ краю:-

 SELECT a.id
FROM some_table a
LEFT OUTER JOIN some_table b
ON a.id = b.id
AND a.media = b.media
AND a.status = 'ACTIVE'
AND b.status = 'PENDING'
WHERE b.id IS NULL
  

Этот self присоединяется к таблице, один для активных и один для ожидающих. Проверяет, что b.id ИМЕЕТ значение NULL для проверки отсутствия совпадения.

Ответ №3:

 SELECT DISTINCT id
  FROM t
 GROUP BY id, media
HAVING MAX(status) = 'ACTIVE';
  

Это предполагает, что идентификатор, который имеет ожидающий носитель, все равно должен быть включен, если он также имеет другой тип носителя без ожидающего. Если это неверно или неприменимо, вы можете удалить DISTINCT из SELECT и media из GROUP BY.

Ответ №4:

Вы можете использовать предложение NOT EXISTS (также подойдет предложение NOT IN).

 select distinct id
from table t
where status = 'ACTIVE'
and not exists (select null
                  from table
                  where t.id = id and t.media = media
                  and status = 'PENDING')
  

смотрите SQLFiddle

Ответ №5:

ОБЪЕДИНЕНИЕ ГРУПП

 select id from tbl group by media,id 
having group_concat(status)='active'
  

Комментарии:

1. Это будет включать строки, содержащие только PENDING .

2. Активен в ожидании чего угодно… я разберусь с этим завтра .. здесь поздняя ночь 🙂

3. Не уверен, какое отношение имеют уникальные наборы к чему-либо, но ваш первый запрос определенно будет включать id запросы, которые имеют только PENDING статусы.

4. Да .. op не упомянул, что ему это нужно только для active … это работает для любого уникального набора… если op нужен конкретный, он может, наконец, добавить предложение where … я предпочитаю общий sql, а не жестко закодированный .. подумайте, прежде чем отклонять

5. отредактировано … OP только что прокомментировал, что он нужен исключительно только для active