【发布时间】:2022-11-27 20:22:01
【问题描述】:
我正在尝试写一个 SELECT 声明第一的加入两个表和然后通过保持每组的最大值来过滤行。
例子
以下两个表格描述了动物园中的访客。
-
visitors表格包括所有去过动物园的独特人物;每人一排。 -
activity_log表格描述了每位游客在参观期间在动物园做了什么;每排一排活动.
生成数据(可重现)
以下 SQL 代码兼容MySQL:
-- visitors
CREATE TABLE visitors(
visitor_id INTEGER NOT NULL PRIMARY KEY,
country_of_birth VARCHAR(7) NOT NULL
);
INSERT INTO visitors(visitor_id, country_of_birth) VALUES
(1, 'Bolivia'),
(2, 'UK'),
(3, 'UK'),
(4, 'Bolivia'),
(5, 'UK'),
(6, 'UK'),
(7, 'France'),
(8, 'USA'),
(9, 'UK'),
(10, 'France');
-- activity_log
CREATE TABLE activity_log(
visitor_id INTEGER NOT NULL,
FOREIGN KEY (visitor_id) REFERENCES visitors(visitor_id),
activity_time DATETIME NOT NULL,
activity_name VARCHAR(14) NOT NULL,
what_was_purchased VARCHAR(8)
);
INSERT INTO activity_log(visitor_id, activity_time, activity_name, what_was_purchased) VALUES
(1, '2020-09-03 11:15:00', 'visit lions', NULL),
(1, '2020-09-03 10:30:00', 'use restroom', NULL),
(1, '2020-09-03 10:10:00', 'visit reptiles', NULL),
(1, '2020-09-03 10:45:00', 'purchase', 'coffee'),
(2, '2021-02-10 15:30:00', 'visit giftshop', NULL),
(2, '2021-02-10 15:02:00', 'visit zebras', NULL),
(2, '2021-02-10 15:45:00', 'visit giraffes', NULL),
(3, '2021-07-07 13:04:00', 'visit reptiles', NULL),
(3, '2021-07-07 13:50:00', 'visit bears', NULL),
(3, '2021-07-07 13:40:00', 'purchase', 'icecream'),
(3, '2021-07-07 14:12:00', 'purchase', 'coffee'),
(4, '2021-08-19 11:33:00', 'visit monkeys', NULL),
(4, '2021-08-19 11:18:00', 'visit lions', NULL),
(4, '2021-08-19 11:47:00', 'use restroom', NULL),
(5, '2022-04-12 10:55:00', 'visit zebras', NULL),
(5, '2022-04-12 11:42:00', 'purchase', 'coffee'),
(5, '2022-04-12 10:45:00', 'purchase', 'hotdog'),
(5, '2022-04-12 11:27:00', 'purchase', 'popcorn'),
(6, '2022-04-12 14:00:00', 'purchase', 'icecream'),
(7, '2022-05-09 12:38:00', 'use restroom', NULL),
(7, '2022-05-09 12:52:00', 'visit reptiles', NULL),
(7, '2022-05-09 12:30:00', 'visit zebras', NULL),
(8, '2022-07-07 15:00:00', 'purchase', 'popcorn'),
(8, '2022-07-07 15:10:00', 'visit birds', NULL),
(9, '2022-07-11 12:13:00', 'purchase', 'popcorn'),
(9, '2022-07-11 11:23:00', 'purchase', 'coffee'),
(9, '2022-07-11 11:00:00', 'visit lions', NULL),
(9, '2022-07-11 11:54:00', 'visit monkeys', NULL),
(10, '2022-08-31 9:30:00', 'use restroom', NULL);
我要的查询
所有购买过东西的英国游客的表格,以及那是什么。如果一个人购买了不止一件东西,请显示最后购买的物品。因此,一个包含 2 列的表:(1) visitor_id,(2) what_was_purchased。
期望的输出
#> +------------+--------------------+
#> | visitor_id | what_was_purchased |
#> +------------+--------------------+
#> | 3 | coffee |
#> | 5 | coffee |
#> | 6 | icecream |
#> | 9 | popcorn |
#> +------------+--------------------+#>
我的尝试
我已经走了这么远,甚至这个似乎也不行:
SELECT *
FROM visitors AS v
LEFT JOIN activity_log AS al ON v.visitor_id = al.visitor_id
AND v.country_of_birth = 'UK'
AND al.visitor_id IN (
SELECT visitor_id
FROM activity_log
GROUP BY visitor_id
HAVING SUM(CASE WHEN what_was_purchased IS NULL THEN 0 ELSE 1 END) > 0
);
-- +------------+------------------+------------+---------------------+----------------+--------------------+
-- | visitor_id | country_of_birth | visitor_id | activity_time | activity_name | what_was_purchased |
-- +------------+------------------+------------+---------------------+----------------+--------------------+
-- | 1 | Bolivia | NULL | NULL | NULL | NULL |
-- | 2 | UK | NULL | NULL | NULL | NULL |
-- | 3 | UK | 3 | 2021-07-07 13:04:00 | visit reptiles | NULL |
-- | 3 | UK | 3 | 2021-07-07 13:50:00 | visit bears | NULL |
-- | 3 | UK | 3 | 2021-07-07 13:40:00 | purchase | icecream |
-- | 3 | UK | 3 | 2021-07-07 14:12:00 | purchase | coffee |
-- | 4 | Bolivia | NULL | NULL | NULL | NULL |
-- | 5 | UK | 5 | 2022-04-12 10:55:00 | visit zebras | NULL |
-- | 5 | UK | 5 | 2022-04-12 11:42:00 | purchase | coffee |
-- | 5 | UK | 5 | 2022-04-12 10:45:00 | purchase | hotdog |
-- | 5 | UK | 5 | 2022-04-12 11:27:00 | purchase | popcorn |
-- | 6 | UK | 6 | 2022-04-12 14:00:00 | purchase | icecream |
-- | 7 | France | NULL | NULL | NULL | NULL |
-- | 8 | USA | NULL | NULL | NULL | NULL |
-- | 9 | UK | 9 | 2022-07-11 12:13:00 | purchase | popcorn |
-- | 9 | UK | 9 | 2022-07-11 11:23:00 | purchase | coffee |
-- | 9 | UK | 9 | 2022-07-11 11:00:00 | visit lions | NULL |
-- | 9 | UK | 9 | 2022-07-11 11:54:00 | visit monkeys | NULL |
-- | 10 | France | NULL | NULL | NULL | NULL |
-- +------------+------------------+------------+---------------------+----------------+--------------------+
-- 19 rows in set (0.00 sec)
解释我的语法
-
我做了
LEFT JOIN activity_log AS al ON v.visitor_id = al.visitor_id AND v.country_of_birth = 'UK'基于 this answer,在连接之前已经只有
UK行。如您所见,效果并不理想,因为我还有其他国家/地区的NULL。但我想我可以用WHERE子句过滤那些。 (但是,我不知道为什么它没有像参考答案中那样被删除)。 -
我做了
AND al.visitor_id IN ( SELECT visitor_id FROM activity_log GROUP BY visitor_id HAVING SUM(CASE WHEN what_was_purchased IS NULL THEN 0 ELSE 1 END) > 0 );过滤在加入之前至少购买过一次的人。在这里,ID 为
2的访客也是空的,应该被删除。
怎么办?
为了这个问题,让我们忽略 NULL 行并假装通过“仅UK”和“至少一次购买”过滤成功:
-- pseudo result I manually edited
-- +------------+------------------+------------+---------------------+----------------+--------------------+
-- | visitor_id | country_of_birth | visitor_id | activity_time | activity_name | what_was_purchased |
-- +------------+------------------+------------+---------------------+----------------+--------------------+
-- | 3 | UK | 3 | 2021-07-07 13:04:00 | visit reptiles | NULL |
-- | 3 | UK | 3 | 2021-07-07 13:50:00 | visit bears | NULL |
-- | 3 | UK | 3 | 2021-07-07 13:40:00 | purchase | icecream |
-- | 3 | UK | 3 | 2021-07-07 14:12:00 | purchase | coffee | |
-- | 5 | UK | 5 | 2022-04-12 10:55:00 | visit zebras | NULL |
-- | 5 | UK | 5 | 2022-04-12 11:42:00 | purchase | coffee |
-- | 5 | UK | 5 | 2022-04-12 10:45:00 | purchase | hotdog |
-- | 5 | UK | 5 | 2022-04-12 11:27:00 | purchase | popcorn |
-- | 6 | UK | 6 | 2022-04-12 14:00:00 | purchase | icecream |
-- | 9 | UK | 9 | 2022-07-11 12:13:00 | purchase | popcorn |
-- | 9 | UK | 9 | 2022-07-11 11:23:00 | purchase | coffee |
-- | 9 | UK | 9 | 2022-07-11 11:00:00 | visit lions | NULL |
-- | 9 | UK | 9 | 2022-07-11 11:54:00 | visit monkeys | NULL |
-- +------------+------------------+------------+---------------------+----------------+--------------------+
我怎样才能让每个人只获得与上次购买对应的行(如activity_time列所示)?请注意,人体内的时间是混乱的。我已经看到 this answer,它似乎就在现场,但我不知道如何将它合并到现有查询中。
【问题讨论】:
标签: mysql sql group-by greatest-n-per-group