SQL逻辑组

时间:2014-02-03 19:18:37

标签: mysql sql

我有一个名为'items'的表(比如这是一个购物清单):

类型: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
  • 我的购物清单中只有肉和水果吗?不,那么只有肉和fruit = 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 |
+----------+-----------+------------+-----+------+-------+-------------------+

有人可以帮助我吗?

感谢。

2 个答案:

答案 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
;

您可以在此处看到与第一个查询中使用的相同的CASE表达式,只是这次它们作为正常的非聚合值返回。这就是您的问题中第一个数据样本的输出结果:

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行,则{ {1}}值也应为0。因此,在实现only_meat逻辑时,我们基本上采用最低meat_only值 - 因此使用is_meat。同样适用于其他两个MIN结果。

*_only结果背后的逻辑可以被视为与前一个结果相反:如果meat列中至少有一个1,结果也应该是1,否则(意思是, “如果所有值都是0”)它应该是0.所以,我们现在要求最大的is_meat值 - 这就是为什么我们使用is_meat作为{{1 }},以及MAXmeat

最后的结果,fruit有点不同,因为它不直接使用“唯一的肉和水果”逻辑,而是使用“无蔬菜”的互补逻辑。我只选择这样做来匹配前面表达式的简单CASE语法,当然,只有因为只有三种类型的项目才有可能。对于更多类型,您可能更愿意直接按指定实现逻辑,为此最好使用搜索的CASE语法而不是简单的CASE语法:

veg

答案 1 :(得分: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

稍微分解一下:

此查询使用多个嵌套选择来构建表,但首先请查看from子句。如果没有嵌套选择(改为使用*),此查询将返回1行1列结果,仅包含1.这并不重要,因为外部from - 子句不是用于任何事情,它需要做的就是返回1行。

然后,查看嵌套选择:

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

此选择通过尝试查找与蔬菜不同的行来检查是否只有蔬菜。如果我们找到这样的行,那么它不是所有的蔬菜,所以我们返回0max只是为了确保我们只得到1行。)如果没有行如果不是3,则返回null

然后第二步是处理null - 值。如果我们得到null,那么我们知道没有类型不同于3的行,因此行必须都是蔬菜。 ifnull的工作原理如下:

ifnull(<some value>, 1)

这意味着如果<some value>为null,它将返回1(函数的第二个参数),如果不是它将返回<some value>。所以,

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

因此,如果我们发现不是蔬菜的东西,内部选择将返回0ifnull函数也将返回null。另一方面,如果内部选择返回1,则行都是蔬菜,因此ifnull应该是最终值,这就是ifnull((select max(1) from Items where type = 3), 0) - 函数返回的内容。

第二种情况是找到是否有蔬菜:

1

基本上反过来说,如果我们发现至少有一行是蔬菜,那么内部选择会返回null,如果我们不这样做,则会null。由于ifnull在这种情况下意味着没有蔬菜,0应该返回{{1}}。

我会留下最后一个来弄清楚自己。