MySQL с пунктом и подсчетом ()

У меня есть следующая таблица, и я пытаюсь получить все: имя, описание, акции, адрес, почтовый индекс и город.

где запас товара 1 > 10 И запас товара 2 > 10 И запас товара 3 > 5

поэтому мне не нужны строки, содержащие только item1 и item2, например строки с ID = 2.

Строки с ID = 1 также не подходят, потому что item1 его запас составляет ‹ 10.

Это означает, что совпадают только строки с идентификаторами 3 и 4. Но я не хочу видеть 6 рядов, мне достаточно двух! содержащий имя, описание, акции, адрес, почтовый индекс, город

| ID | NAME | DESCR | STOCK | ADDRESS | POSTALCODE | CITY |
|  1  |  foo  |  item1 |  5 |  addr1 |  po1 | city1 |
| 1  | foo  | item2 | 10 | addr1 | po1 | city1 |
| 1  | foo  | item3 | 5 | addr1 | po1 | city1 |
| 2  | bar  | item1 | 40 | addr2 | po1 | city1 |
| 2  | bar  | item2 | 30 | addr2 | po1 | city1 |
| 3  | smth  | item1 | 25 | addr3 | po3 | city1 |
| 3  | smth  | item2 | 20 | addr3 | po3 | city1 |
| 3  | smth  | item3 | 10 | addr3 | po3 | city1 |
| 4  | els  | item1 | 45 | addr4 | po4 | city1 |
| 4  | els  | item2 | 30 | addr4 | po4 | city1 |
| 4  | els  | item3 | 10 | addr4 | po4 | city1 |

Я думаю, мне нужно что-то вроде:

SELECT name, descr, stock , address, postalcode, city
FROM table1
WHERE (descr like 'item1' AND stock >10) 
OR (descr like 'item2' AND stock >10) OR (descr like 'item3' AND stock >5)
GROUP BY name, descr, stock , address, postalcode, city
HAVING COUNT(distinct(somethingIdidNotFigureOutYet)) > 2

Я пытался посчитать id, имя и даже описание, но это неправильно. Может ли кто-нибудь помочь мне с этим, пожалуйста. Благодарю вас! (и извините за уродливое форматирование таблицы)


person b101    schedule 11.01.2016    source источник
comment
Какие две строки вы хотите увидеть, когда шесть строк соответствуют вашим условиям?   -  person Gordon Linoff    schedule 11.01.2016


Ответы (4)


Я обычно подхожу к подобным проблемам, разбивая их на более мелкие группы, а затем объединяя запросы по мере необходимости. Давайте рассмотрим несколько вещей:

  • Запас позиции 1, позиции 2 должен быть больше 10, а запас позиции 3 должен быть больше 5.

Мы можем получить строки, соответствующие этим требованиям, следующим образом:

SELECT id
FROM myTable
GROUP BY id
HAVING 
  SUM(CASE WHEN descr = 'item1' THEN stock else 0 END) > 10 AND 
  SUM(CASE WHEN descr = 'item2' THEN stock else 0 END) > 10 AND 
  SUM(CASE WHEN descr = 'item3' THEN stock else 0 END) > 5;

Это вернет идентификаторы 3 и 4. По совпадению, это также будет работать для выполнения условия, что у нас должен быть хотя бы один элемент1, элемент2 и элемент3, поскольку мы использовали «И» в нашем предложении наличия, что и привело к его исключению. идентификатор 2.

Вот пример SQL Fiddle.

person AdamMc331    schedule 11.01.2016
comment
DISTINCT в вашем запросе довольно бесполезно - person Pரதீப்; 11.01.2016
comment
Я полагаю, что после того, как я добавил GROUP BY. - person AdamMc331; 11.01.2016
comment
@McAdam331 Большое спасибо! работал как шарм. Также я хотел бы всем остальным за их усилия! - person b101; 11.01.2016

Учитывая фильтр WHERE в этом случае, вы можете ограничить группы наборов результатов этими HAVING COUNT(DISTINCT descr) = 3 (или, если descr обязательно уникален в каждой группе, просто HAVING COUNT(*) = 3).

Однако более общим решением может быть явная проверка того, что каждый критерий удовлетворяется каждой группой:

HAVING SUM(descr = 'item1' AND stock > 10)
   AND SUM(descr = 'item2' AND stock > 10)
   AND SUM(descr = 'item3' AND stock >  5)

Это работает, потому что логические выражения внутри каждого SUM() оцениваются как 1, если истина, и 0, если ложь; поэтому использование SUM() для каждой группы приводит к 0, если false для всех записей, или ненулевому, если true для любой (и при использовании в логическом контексте предложения ANDoperations/HAVING дает желаемый результат).

Хотя на набор результатов это не повлияет, я бы все же сохранил предложение WHERE из соображений производительности.

person eggyal    schedule 11.01.2016

Если вам нужны имена и адресная информация, вы можете использовать пункт HAVING, но вы также должны исправить пункт GROUP BY. Вот пример:

SELECT name, address, postalcode, city
FROM table1
GROUP BY name, address, postalcode, city
HAVING SUM(CASE WHEN descr like 'item1' THEN stock END) > 10 AND
       SUM(CASE WHEN descr like 'item2' THEN stock END) > 10 AND
       SUM(CASE WHEN descr like 'item3' THEN stock END) > 5; 

Примечание. Я только что переместил все условия в предложение HAVING, поэтому логика фильтрации находится в одном месте. Вы можете повторить это в предложении WHERE, если хотите.

Затем, если вам нужны описания и количество запасов, одним из методов является список:

SELECT name, address, postalcode, city,
       GROUP_CONCAT(descr, ':', stock SEPARATOR '; ') as items
FROM table1
GROUP BY name, address, postalcode, city
HAVING SUM(CASE WHEN descr like 'item1' THEN stock END) > 10 AND
       SUM(CASE WHEN descr like 'item2' THEN stock END) > 10 AND
       SUM(CASE WHEN descr like 'item3' THEN stock END) > 5; 

Если вам нужны исходные строки, я бы предложил IN или EXISTS:

select t.*
from table1 t
where exists (select 1
              from table1 t1
              where t1.id = t.id and t1.descr = 'item1' and t1.stock > 10
             ) and
      exists (select 1
              from table1 t1
              where t1.id = t.id and t1.descr = 'item2' and t1.stock > 10
             ) and
      exists (select 1
              from table1 t1
              where t1.id = t.id and t1.descr = 'item3' and t1.stock > 5
             ) and
      t.descr in ('item1', 'item2', 'item3');

Примечание: в этой версии предполагается, что элементы не повторяются для данного id. Первая версия не делает этого предположения.

person Gordon Linoff    schedule 11.01.2016
comment
Есть ли преимущество в использовании CASE WHEN descr LIKE 'item1' вместо WHEN descr = 'item1' или это просто личное предпочтение? - person AdamMc331; 11.01.2016
comment
@ МакАдам331 . . . Я почти никогда не использую простой оператор case, потому что слишком часто обнаруживал, что логика должна быть изменена для искомого случая. Проще просто написать искомую версию случая в первый раз. - person Gordon Linoff; 11.01.2016
comment
Это имеет смысл, так что это более «масштабируемо» в этом отношении, его легче изменить в будущем? - person AdamMc331; 11.01.2016
comment
@GordonLinoff большое спасибо! Я очень ценю это !! - person b101; 11.01.2016

Вам нужно удалить descr из select и group by и добавить его в предложение Having для фильтрации групп.

Попробуй это.

SELECT ID,
       NAME, 
       stock, 
       address, 
       postalcode, 
       city 
FROM   table1 
WHERE  ( descr IN ( 'item1', 'item2' ) 
         AND stock > 10 ) 
        OR ( descr = 'item3' 
             AND stock > 5 ) 
GROUP  BY ID,
          NAME, 
          stock, 
          address, 
          postalcode, 
          city 
HAVING Count(DISTINCT descr) = 3

Примечание. Использование оператора LIKE без подстановочных знаков не имеет смысла, поэтому я заменил его на оператор =.

person Pரதீப்    schedule 11.01.2016