В данном случае мне нужно только objid = 2 т.к. у всех значений status=0. При этом objid 1 и 3 не подходят, т.к. у 3 status=1 а у 1 статус у некоторых равен 1, а у некоторых 0.
Да по идее можно взять те, что равны 1 и исключить эти ID из выборки. Но давайте представим, что таких с 1 около 100 тысяч записей, и в подзапросе их исключать будет накладно.
Возможно ли сказать mysql, что не нужны все objid где status не равен 0? Ну или же, если перефразировать - исключить все objid, если у них есть хотя бы одно значение равно 1?
Даже вот предположим, что мы получили список тех, где есть хотя бы один ноль - как убрать из этого списка все записи с одинаковыми objid где есть хотя бы одна единица?
PS. Статусов может быть не 2 а больше. Например 5 статусов. Нужно получить те objid где есть статус 0 и 4 но нет статусов 1 2 и 3.
Не совсем то что нужно. Дело в том, что статусов на самом деле может быть много (видимо зря я это не указал) и нужно выбрать определенные комбинации, когда objid подходит и когда не подходит (все остальные значения)
Также нужно учитывать, что в таблице может несколько миллионов записей, а по параметрам подходят около 10 тысяч, однако после отсеивания получается всего около тысячи.
Stalker_RED: добавил. Я кстати попробовал вариант с исключением с подзапросами и т.д. но вышло в итоге 3 подзапроса вложенных что на большом числе данных очень медленно
explain SELECT objid, count(DISTINCT status) as cnt
FROM q280781 t1
WHERE status IN (0,4) -- эти необходимы
AND NOT EXISTS (SELECT * FROM q280781 t2
WHERE t2.objid=t1.objid
AND status IN (1,2,3,5)) -- этих быть НЕ может
GROUP BY objid
HAVING cnt = 2 -- кол-во необходимых статусов (что-бы срабатывало как 0 and 4 а не 0 or 4)
Stalker_RED: Как то все тоже плохо - тех что не нужны всегда больше. Я сделал так:
SELECT count(DISTINCT t.objid) FROM
(SELECT objid,status FROM `table` WHERE status=4 OR status=0 ORDER BY id desc) as t
WHERE t.objid not in (SELECT objid,status FROM `table` WHERE status=4 OR status=0 ORDER BY id desc) as t, table
WHERE t.objid=table.objid AND (table.status=1 OR table.status=2 OR table.status=3))
Это если их нужно посчитать. Но и получить их не сложно будет.
Дело в том, что записей в таблице всего несколько миллионов. Там есть еще дополнительные условия для выборки пользователя и на крупных пользователях получается что записей со всеми статусами может быть больше 100 тысяч.
Но если делать как в этом запросе - то мы сразу проверяем только те, что нам могут подойти. Что несколько экономит ресурсы. Я еще буду тестировать, посмотрим что будет эффективнее. Но может как то можно это оптимизировать?
PS. GROUP BY самая жирная операция, я тут недавно еще тестами занимался по этому поводу, можно сделать еще один подзапрос, чтобы сначала сделать LIMIT например до 1000 и уже на этом делать GROUP BY если записей много. Изначально же он сначала группирует, а потом делает LIMIT. Т.е. если нам нужно получить всего 10 записей,то нет смысла группировать 100 тысяч, достаточно 200-1000 где найдем эти 10 уникальных.
Для правильного вопроса надо знать половину ответа
SELECT `objid`
FROM `table`
GROUP BY `objid`
HAVING MAX(`status`) = 0
SELECT DISTINCT `t1`.`objid`
FROM `table` AS `t1`
LEFT JOIN (
SELECT DISTINCT `objid`
FROM `table`
WHERE `status` = 1
) AS `t2` USING(`objid`)
WHERE `t2`.`objid` IS NULL
Немного перефразирую второй селект:
SELECT DISTINCT `t1`.`objid`
FROM `table` AS `t1`
LEFT JOIN `table` AS `t2` on `t2`.`objid`=`t1`.`objid` and `t2`.`status` > 0
WHERE `t2`.`objid` IS NULL