我有一个名为'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 |
+----------+-----------+------------+-----+------+-------+-------------------+
逻辑:
另一个例子:
+----+---------+------+
| 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 :(得分: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 }},以及MAX
和meat
。
最后的结果,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)
此选择通过尝试查找与蔬菜不同的行来检查是否只有蔬菜。如果我们找到这样的行,那么它不是所有的蔬菜,所以我们返回0
(max
只是为了确保我们只得到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)
因此,如果我们发现不是蔬菜的东西,内部选择将返回0
,ifnull
函数也将返回null
。另一方面,如果内部选择返回1
,则行都是蔬菜,因此ifnull
应该是最终值,这就是ifnull((select max(1) from Items where type = 3), 0)
- 函数返回的内容。
第二种情况是找到是否有蔬菜:
1
基本上反过来说,如果我们发现至少有一行是蔬菜,那么内部选择会返回null
,如果我们不这样做,则会null
。由于ifnull
在这种情况下意味着没有蔬菜,0
应该返回{{1}}。
我会留下最后一个来弄清楚自己。