MySQL 交叉表/数据透视聚合。根据其他 table 中的列删除计数
MySQL Crosstab / Pivot Aggregation. Removing counts based on column in other table
数据
我有一组数据,格式如下:
CAR_INVENTORY TABLE
CAR_ID MAKE_MODEL COLOR YEAR
1 Ford Fusion Black 2015
2 Tesla Model S White 2014
3 Acura ILX Blue 2013
4 Ford Fusion Black 2013
5 Toyota Corolla Blue 2014
6 Ford Fusion Blue 2013
7 Toyota Corolla Blue 2012
8 Acura ILX Black 2015
9 Ford Focus Blue 2012
10 Ford Fusion White 2013
11 Acura ILX Black 2012
12 Toyota Corolla Black 2015
13 Toyota Corolla Blue 2014
14 Ford Focus White 2015
15 Tesla Model S Red 2015
16 Acura TLX White 2014
17 Toyota Corolla Blue 2014
18 Ford Focus Black 2013
INVENTORY_LOG TABLE
LOG_ID CAR_ID NOTE
1 7 Issue with Fuel Guage
2 3 Sweet Ride
3 16 Zippy
4 14 Issue with transmission
5 3 Fun to Drive
6 2 *NULL*
7 8 *NULL*
8 10 Economic
9 15 WOW
10 9 Good Fuel Economy
11 16 Minor issue with Shifting
12 7 Issue with Airbag
13 17 Great Mileage
14 1 Nice Tech
15 13 *NULL*
16 11 Trunk is small
17 12 *NULL*
18 2 Very Speedy
19 7 Good Mileage
20 10 Roomy
21 4 *NULL*
22 6 Nice Tech Package
23 5 Good Economy
24 18 Cool
我知道它还没有完全标准化。假设我不能弄乱数据。
car_inventory table 一行对应每辆库存车。 inventory_log table 对 car_inventory 中列出的每辆车至少有一个条目,因此每辆车可能有很多日志条目。 inventory_log 中的条目可以为空。
到目前为止我做了什么
如果一辆车的日志中有单词 'issue',则需要对其进行标记。我已经弄清楚了那部分:
SELECT
ci.car_id,
CONCAT(ci.color, " ", ci.make_model) as car,
SUM(IF (LOWER(il.note) LIKE '%issue%', TRUE, FALSE)) AS issue
FROM car_inventory ci
LEFT JOIN inventory_log il USING (car_id)
GROUP BY ci.car_id
ORDER BY ci.car_id;
这年:
car_id car issue
1 Black Ford Fusion 0
2 White Tesla Model S 0
3 Blue Acura ILX 0
4 Black Ford Fusion 0
5 Blue Toyota Corolla 0
6 Blue Ford Fusion 0
7 Blue Toyota Corolla 2
8 Black Acura ILX 0
9 Blue Ford Focus 0
10 White Ford Fusion 0
11 Black Acura ILX 0
12 Black Toyota Corolla 0
13 Blue Toyota Corolla 0
14 White Ford Focus 1
15 Red Tesla Model S 0
16 White Acura TLX 1
17 Blue Toyota Corolla 0
18 Black Ford Focus 0
这对任何有问题的汽车给出了非零结果。
接下来我需要做的是在特定年份之后按颜色统计所有品牌。假设我们只对黑色、白色和蓝色感兴趣,并且我们只有福特、讴歌、丰田和特斯拉(我知道我可以使用准备好的语句来实现动态)。包里也有那个:
SELECT
CASE
WHEN ci.make_model LIKE "Acura%" THEN "Acura"
WHEN ci.make_model LIKE "Ford%" THEN "Ford"
WHEN ci.make_model LIKE "Toyota%" THEN "Toyota"
WHEN ci.make_model LIKE "Tesla%" THEN "Tesla"
END AS Make,
SUM(CASE WHEN ci.color = "Black" THEN 1 ELSE 0 END) as Black,
SUM(CASE WHEN ci.color = "Blue" THEN 1 ELSE 0 END) as Blue,
SUM(CASE WHEN ci.color = "White" THEN 1 ELSE 0 END) as White
FROM car_inventory ci
LEFT JOIN inventory_log il USING (car_id)
WHERE
ci.year > 2012
GROUP BY Make
ORDER BY Make;
这给了我:
Make Black Blue White
Acura 1 1 1
Ford 3 1 2
Tesla 0 0 1
Toyota 1 3 0
快速统计 car_inventory table,有 14 辆比 2012 年更新的汽车,分别是黑色、蓝色或白色。
问题
这是我遇到问题的地方:
我想做的是将两者结合起来。我需要按颜色计算所有品牌,没有问题。
这是我试图获得的结果集:
DESIRED RESULT
MAKE Black Blue White
Acura 1 1 0
Ford 3 1 1
Tesla 0 0 1
Toyota 1 2 0
删除了以下三辆车:
car_id car issues
7 Blue Toyota Corolla 2
14 White Ford Focus 1
16 White Acura TLX 1
我试过将 AND SUM(IF (LOWER(il.note) LIKE '%issue%', TRUE, FALSE)) = 0
添加到 where 子句中。这会导致 mysql 错误 1111 "Invalid use of group function".
我也试过 HAVING SUM(IF (LOWER(il.note) LIKE '%issue%', TRUE, FALSE)) != 0
。它产生了错误的结果,只显示了特斯拉和丰田的行。
问题
如何在 MySQL 中创建交叉表查询,以便汽车(来自 car_inventory)的日志条目(来自 inventory_log)包含单词 'issue'其中不算数?
所以我想出了如何使用子查询来做到这一点:
SELECT
CASE
WHEN ci.make_model LIKE "Acura%" THEN "Acura"
WHEN ci.make_model LIKE "Ford%" THEN "Ford"
WHEN ci.make_model LIKE "Toyota%" THEN "Toyota"
WHEN ci.make_model LIKE "Tesla%" THEN "Tesla"
END AS Make,
SUM(CASE WHEN ci.color = "Black" THEN 1 ELSE 0 END) as Black,
SUM(CASE WHEN ci.color = "Blue" THEN 1 ELSE 0 END) as Blue,
SUM(CASE WHEN ci.color = "White" THEN 1 ELSE 0 END) as White
FROM (
SELECT
ci2.car_id,
ci2.make_model,
ci2.color
FROM car_inventory ci2
LEFT JOIN inventory_log il2 USING (car_id)
WHERE
ci2.year > 2012
GROUP BY ci2.car_id
HAVING SUM(IF (LOWER(il2.note) LIKE '%issue%', TRUE, FALSE)) = 0
) as ci
GROUP BY Make
ORDER BY Make;
这给了我:
Make Black Blue White
Acura 1 1 0
Ford 3 1 1
Tesla 0 0 1
Toyota 1 3 0
我不会将此标记为已接受的答案,因为我很确定有一种更好、更高效的方法可以在没有子查询的情况下执行此操作。
SELECT
CASE
WHEN ci.make_model LIKE "Acura%" THEN "Acura"
WHEN ci.make_model LIKE "Ford%" THEN "Ford"
WHEN ci.make_model LIKE "Toyota%" THEN "Toyota"
WHEN ci.make_model LIKE "Tesla%" THEN "Tesla"
END AS Make,
SUM(CASE WHEN ci.color = "Black" THEN 1 ELSE 0 END) as Black,
SUM(CASE WHEN ci.color = "Blue" THEN 1 ELSE 0 END) as Blue,
SUM(CASE WHEN ci.color = "White" THEN 1 ELSE 0 END) as White
FROM car_inventory ci
WHERE
(ci.year > 2012) and
(ci.car_id not in (select distinct il.car_id from inventory_log il where il.note like '%issue%'))
GROUP BY Make
ORDER BY Make;
数据
我有一组数据,格式如下:
CAR_INVENTORY TABLE
CAR_ID MAKE_MODEL COLOR YEAR
1 Ford Fusion Black 2015
2 Tesla Model S White 2014
3 Acura ILX Blue 2013
4 Ford Fusion Black 2013
5 Toyota Corolla Blue 2014
6 Ford Fusion Blue 2013
7 Toyota Corolla Blue 2012
8 Acura ILX Black 2015
9 Ford Focus Blue 2012
10 Ford Fusion White 2013
11 Acura ILX Black 2012
12 Toyota Corolla Black 2015
13 Toyota Corolla Blue 2014
14 Ford Focus White 2015
15 Tesla Model S Red 2015
16 Acura TLX White 2014
17 Toyota Corolla Blue 2014
18 Ford Focus Black 2013
INVENTORY_LOG TABLE
LOG_ID CAR_ID NOTE
1 7 Issue with Fuel Guage
2 3 Sweet Ride
3 16 Zippy
4 14 Issue with transmission
5 3 Fun to Drive
6 2 *NULL*
7 8 *NULL*
8 10 Economic
9 15 WOW
10 9 Good Fuel Economy
11 16 Minor issue with Shifting
12 7 Issue with Airbag
13 17 Great Mileage
14 1 Nice Tech
15 13 *NULL*
16 11 Trunk is small
17 12 *NULL*
18 2 Very Speedy
19 7 Good Mileage
20 10 Roomy
21 4 *NULL*
22 6 Nice Tech Package
23 5 Good Economy
24 18 Cool
我知道它还没有完全标准化。假设我不能弄乱数据。
car_inventory table 一行对应每辆库存车。 inventory_log table 对 car_inventory 中列出的每辆车至少有一个条目,因此每辆车可能有很多日志条目。 inventory_log 中的条目可以为空。
到目前为止我做了什么
如果一辆车的日志中有单词 'issue',则需要对其进行标记。我已经弄清楚了那部分:
SELECT
ci.car_id,
CONCAT(ci.color, " ", ci.make_model) as car,
SUM(IF (LOWER(il.note) LIKE '%issue%', TRUE, FALSE)) AS issue
FROM car_inventory ci
LEFT JOIN inventory_log il USING (car_id)
GROUP BY ci.car_id
ORDER BY ci.car_id;
这年:
car_id car issue
1 Black Ford Fusion 0
2 White Tesla Model S 0
3 Blue Acura ILX 0
4 Black Ford Fusion 0
5 Blue Toyota Corolla 0
6 Blue Ford Fusion 0
7 Blue Toyota Corolla 2
8 Black Acura ILX 0
9 Blue Ford Focus 0
10 White Ford Fusion 0
11 Black Acura ILX 0
12 Black Toyota Corolla 0
13 Blue Toyota Corolla 0
14 White Ford Focus 1
15 Red Tesla Model S 0
16 White Acura TLX 1
17 Blue Toyota Corolla 0
18 Black Ford Focus 0
这对任何有问题的汽车给出了非零结果。
接下来我需要做的是在特定年份之后按颜色统计所有品牌。假设我们只对黑色、白色和蓝色感兴趣,并且我们只有福特、讴歌、丰田和特斯拉(我知道我可以使用准备好的语句来实现动态)。包里也有那个:
SELECT
CASE
WHEN ci.make_model LIKE "Acura%" THEN "Acura"
WHEN ci.make_model LIKE "Ford%" THEN "Ford"
WHEN ci.make_model LIKE "Toyota%" THEN "Toyota"
WHEN ci.make_model LIKE "Tesla%" THEN "Tesla"
END AS Make,
SUM(CASE WHEN ci.color = "Black" THEN 1 ELSE 0 END) as Black,
SUM(CASE WHEN ci.color = "Blue" THEN 1 ELSE 0 END) as Blue,
SUM(CASE WHEN ci.color = "White" THEN 1 ELSE 0 END) as White
FROM car_inventory ci
LEFT JOIN inventory_log il USING (car_id)
WHERE
ci.year > 2012
GROUP BY Make
ORDER BY Make;
这给了我:
Make Black Blue White
Acura 1 1 1
Ford 3 1 2
Tesla 0 0 1
Toyota 1 3 0
快速统计 car_inventory table,有 14 辆比 2012 年更新的汽车,分别是黑色、蓝色或白色。
问题
这是我遇到问题的地方:
我想做的是将两者结合起来。我需要按颜色计算所有品牌,没有问题。
这是我试图获得的结果集:
DESIRED RESULT
MAKE Black Blue White
Acura 1 1 0
Ford 3 1 1
Tesla 0 0 1
Toyota 1 2 0
删除了以下三辆车:
car_id car issues
7 Blue Toyota Corolla 2
14 White Ford Focus 1
16 White Acura TLX 1
我试过将 AND SUM(IF (LOWER(il.note) LIKE '%issue%', TRUE, FALSE)) = 0
添加到 where 子句中。这会导致 mysql 错误 1111 "Invalid use of group function".
我也试过 HAVING SUM(IF (LOWER(il.note) LIKE '%issue%', TRUE, FALSE)) != 0
。它产生了错误的结果,只显示了特斯拉和丰田的行。
问题
如何在 MySQL 中创建交叉表查询,以便汽车(来自 car_inventory)的日志条目(来自 inventory_log)包含单词 'issue'其中不算数?
所以我想出了如何使用子查询来做到这一点:
SELECT
CASE
WHEN ci.make_model LIKE "Acura%" THEN "Acura"
WHEN ci.make_model LIKE "Ford%" THEN "Ford"
WHEN ci.make_model LIKE "Toyota%" THEN "Toyota"
WHEN ci.make_model LIKE "Tesla%" THEN "Tesla"
END AS Make,
SUM(CASE WHEN ci.color = "Black" THEN 1 ELSE 0 END) as Black,
SUM(CASE WHEN ci.color = "Blue" THEN 1 ELSE 0 END) as Blue,
SUM(CASE WHEN ci.color = "White" THEN 1 ELSE 0 END) as White
FROM (
SELECT
ci2.car_id,
ci2.make_model,
ci2.color
FROM car_inventory ci2
LEFT JOIN inventory_log il2 USING (car_id)
WHERE
ci2.year > 2012
GROUP BY ci2.car_id
HAVING SUM(IF (LOWER(il2.note) LIKE '%issue%', TRUE, FALSE)) = 0
) as ci
GROUP BY Make
ORDER BY Make;
这给了我:
Make Black Blue White
Acura 1 1 0
Ford 3 1 1
Tesla 0 0 1
Toyota 1 3 0
我不会将此标记为已接受的答案,因为我很确定有一种更好、更高效的方法可以在没有子查询的情况下执行此操作。
SELECT
CASE
WHEN ci.make_model LIKE "Acura%" THEN "Acura"
WHEN ci.make_model LIKE "Ford%" THEN "Ford"
WHEN ci.make_model LIKE "Toyota%" THEN "Toyota"
WHEN ci.make_model LIKE "Tesla%" THEN "Tesla"
END AS Make,
SUM(CASE WHEN ci.color = "Black" THEN 1 ELSE 0 END) as Black,
SUM(CASE WHEN ci.color = "Blue" THEN 1 ELSE 0 END) as Blue,
SUM(CASE WHEN ci.color = "White" THEN 1 ELSE 0 END) as White
FROM car_inventory ci
WHERE
(ci.year > 2012) and
(ci.car_id not in (select distinct il.car_id from inventory_log il where il.note like '%issue%'))
GROUP BY Make
ORDER BY Make;