2014-02-03 7 views
-1

У меня есть таблица под названием 'элементы' (скажем, это список покупок):SQL логические группы

Типы: 1. мясо, 2. фрукты, 3. Вег

+----+----------+------+ 
| id | item | type | 
+----+----------+------+ 
| 1 | chicken | 1 | 
| 2 | orange | 2 | 
| 3 | apple | 2 | 
| 4 | beef  | 1 | 
| 5 | potatoes | 3 | 
| 6 | lamb  | 1 | 
| 7 | tomatoes | 3 | 
| 8 | cucumber | 3 | 
| 9 | pork  | 1 | 
| 10 | pear  | 2 | 
| 11 | beans | 3 | 
+----+----------+------+ 

И я хотел бы получить следующую логическую таблицу:

+----------+-----------+------------+-----+------+-------+-------------------+ 
| only veg | only meat | only fruit | veg | meat | fruit | only meat & fruit | 
+----------+-----------+------------+-----+------+-------+-------------------+ 
|  0 |   0 |   0 | 1 | 1 |  1 |     0 | 
+----------+-----------+------------+-----+------+-------+-------------------+ 

Логика:

  • У меня есть только овощи в моем списке? Нет. Тогда только veg = 0
  • У меня есть только мясо в моем списке покупок? Нет. Тогда только мясо = 0
  • У меня есть только фрукты в моем списке покупок? Нет. Тогда только фрукты = 0
  • У меня есть овощи в моем списке покупок? Да. Затем veg = 1
  • У меня есть мясо в моем списке покупок? Да. Тогда, мясо = 1
  • У меня есть фрукты в моем списке покупок? Да. Затем фрукты = 1
  • У меня есть только мясо и фрукты в моем списке покупок? Нет. Тогда только мясо & фрукты = 0

Другой пример:

+----+---------+------+ 
| id | item | type | 
+----+---------+------+ 
| 1 | chicken | 1 | 
| 2 | orange | 2 | 
| 3 | apple | 2 | 
| 4 | beef | 1 | 
+----+---------+------+ 

Результат:

+----------+-----------+------------+-----+------+-------+-------------------+ 
| only veg | only meat | only fruit | veg | meat | fruit | only meat & fruit | 
+----------+-----------+------------+-----+------+-------+-------------------+ 
|  0 |   0 |   0 | 0 | 1 |  1 |     1 | 
+----------+-----------+------------+-----+------+-------+-------------------+ 

Может кто-нибудь помочь мне?

Спасибо.

+0

Каковы цифры в результате? – Tobb

+0

0 = False 1 = True – cornell

+5

Что еще более важно, являются ли помидоры овощами или фруктами? – RedFilter

ответ

0
select  
    ifnull((select max(0) from Items where type <> 3), 1) as "only veg", 
    ifnull((select max(0) from Items where type <> 1), 1) as "only meat", 
    ifnull((select max(0) from Items where type <> 2), 1) as "only fruit", 
    ifnull((select max(1) from Items where type = 3), 0) as "veg", 
    ifnull((select max(1) from Items where type = 1), 0) as "meat", 
    ifnull((select max(1) from Items where type = 2), 0) as "fruit", 
    ifnull((select max(0) from Items where type = 3), 1) as "only meat and fruit" 
from (select 1) as p 

Это мое решение. Вы можете попробовать это самостоятельно, вставив его здесь: http://sqlfiddle.com/#!2/5be90

Это написано на диалекте MySQL, если вы используете что-то еще, вам, возможно, придется обменять ifnull с помощью isnull.

Чтобы разбить его немного:

Этот запрос использует несколько вложенных выбирает для построения таблицы, но позволяет первый взгляд на от пункта. Без вложенных выборок (вместо этого вместо *) этот запрос будет возвращать результат столбца 1 строки 1, содержащий только 1. Это не имеет большого значения, поскольку внешний from -clause не используется ни для чего, все, что ему нужно do возвращается 1 строка.

Затем, глядя на вложенном выбирает:

(select max(0) from Items where type <> 3) 

этого выделит проверяет, есть только овощи, пытаясь найти строку, которая является чем-то отличается от овоща. Если мы найдем такую ​​строку, то это не все овощи, поэтому мы возвращаем 0 (max вещь просто для того, чтобы убедиться, что мы получаем только 1 строку.) Если нет строк с типом, отличным от 3, он вернется null.

Второй этап заключается в обработке значения null. Если мы получим null, то мы знаем, что нет строк с типом, отличным от 3, и поэтому все строки должны быть овощами. В ifnull работает так:

ifnull(<some value>, 1) 

Это означает, что если <some value> имеет нулевое значение, он будет возвращать 1 (второй параметр функции), если его не будет возвращать <some value>. Так,

ifnull((select max(0) from Items where type <> 3), 1) 

Так что, если мы находим то, что это не овощ, внутренний выбор будет возвращать 0, и так будет функция ifnull. Если внутренний выбор возвращает null, то в строках все овощи, поэтому 1 должно быть окончательным значением, и это то, что возвращает ifnull -функция.

Второй случай обнаружения, если есть любые овощи:

ifnull((select max(1) from Items where type = 3), 0) 

Вот это наоборот в основном, внутренние выберите возвращает 1 если мы найдем хотя бы одну строку, что это овощ, null если мы не «т. Так как null в этом случае означает, что овощей нет, ifnull должен вернуть 0.

Я оставлю последний, чтобы выяснить себя.

1

Ниже несколько похожа на @Tobb's suggestion, но с помощью этого метода таблица сканируется только один раз:

SELECT 
    MIN(CASE type WHEN 1 THEN 1 ELSE 0 END) AS meat_only, 
    MIN(CASE type WHEN 2 THEN 1 ELSE 0 END) AS fruit_only, 
    MIN(CASE type WHEN 3 THEN 1 ELSE 0 END) AS veg_only, 

    MAX(CASE type WHEN 1 THEN 1 ELSE 0 END) AS meat, 
    MAX(CASE type WHEN 2 THEN 1 ELSE 0 END) AS fruit, 
    MAX(CASE type WHEN 3 THEN 1 ELSE 0 END) AS veg, 

    MIN(CASE type WHEN 3 THEN 0 ELSE 1 END) AS meat_and_fruit_only 
FROM items 
; 

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

Если вы еще не знакомы с условной агрегацией, между AGG(CASE ... END) и AGG(column) нет большой разницы. В обоих случаях аргумент представляет собой столбец значений, только в первом случае столбец - это тот, который вычисляется во время выполнения с помощью выражения CASE.

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

SELECT 
    *, 
    CASE type WHEN 1 THEN 1 ELSE 0 END AS is_meat, 
    CASE type WHEN 2 THEN 1 ELSE 0 END AS is_fruit, 
    CASE type WHEN 3 THEN 1 ELSE 0 END AS is_veg 
FROM items 
; 

Вы можете увидеть тот же случай выражения здесь, как используется в первом запросе, только на этот раз они возвращаются в нормальные, неагрегированные столбцы значений. Это то, что выход будет выглядеть для первой выборки данных в вашем вопросе:

id item  type is_meat is_fruit is_veg 
-- -------- ---- ------- -------- ------ 
1 chicken  1  1   0  0 
2 orange  2  0   1  0 
3 apple  2  0   1  0 
4 beef   1  1   0  0 
5 potatoes  3  0   0  1 
6 lamb   1  1   0  0 
7 tomatoes  3  0   0  1 
8 cucumber  3  0   0  1 
9 pork   1  1   0  0 
10 pear   2  0   1  0 
11 beans  3  0   0  1 

На основании вышеизложенного вывод, логика первого запроса может быть проще понять. Например, meat_only должно быть 1, если все значения is_meat во втором запросе равны 1, в противном случае это должно быть 0. Другими словами, если есть хотя бы одна строка is_meat = 0, значение only_meat также должно быть 0. Поэтому при реализации логики meat_only мы по существу стремимся к наименьшему значению is_meat - следовательно, к использованию MIN. То же самое относится к другим двум результатам *_only.

Логика meat результата можно рассматривать как противоположность предыдущего: если есть по крайней мере один 1 в is_meat столбце, результат должен быть 1 тоже, в противном случае (что означает, «если все значения 0 "), это должно быть 0. Итак, мы собираемся достичь наибольшего значения is_meat - вот почему мы используем MAX для meat, а также fruit и veg.

Последний результат, meat_and_fruit_only немного отличается тем, что он не использует только «только мясо & фрукты», а вместо этого использует дополнительную логику «без овощей». Я только решил сделать это, чтобы сопоставить простой синтаксис CASE предыдущих выражений и, конечно же, это было возможно только из-за того, что существует только три типа элементов. С большим количеством типов вы могли бы, вероятно, предпочитаете реализовать логику непосредственно, как указано, для которых было бы лучше использовать найденную синтаксис CA, а не простой случай один:

MIN(CASE WHEN type IN (1, 2) THEN 1 ELSE 0 END) AS meat_and_fruit_only