MySQL --- 在同一个 table 上设置减号和相交操作
MySQL --- set operations MINUS and INTERSECT on the same table
我们需要跟踪随时间变化的集成员资格。我可以用以下简单的 table:
来解释我们的问题
+-----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| timestamp | varchar(8) | NO | | NULL | |
| member | varchar(4) | NO | | NULL | |
+-----------+------------------+------+-----+---------+----------------+
SELECT*运算结果如下:
SELECT * FROM My_Table;
+----+-----------+--------+
| id | timestamp | member |
+----+-----------+--------+
| 1 | 20150101 | A |
| 2 | 20150101 | B |
| 3 | 20150101 | C |
| 4 | 20180101 | A |
| 5 | 20180101 | D |
| 6 | 20180101 | E |
+----+-----------+--------+
从逻辑上讲,我们可以使用 SET 操作 MINUS 和 INTERSECT 来了解在一段时间内添加、删除或保留了哪些成员。例如,下面的 "logical" 集合操作给出了在 20150101 和 20180101 之间添加的成员数:
SELECT member FROM my_table WHERE timestamp = "20180101"
MINUS
SELECT member FROM my_table WHERE timestamp = "20150101";
同样,下面的"logical"设置操作给出了20150101到20180101之间掉线的成员数:
SELECT member FROM my_table WHERE timestamp = "20150101"
MINUS
SELECT member FROM my_table WHERE timestamp = "20180101";
下面的"logical"集合运算给出了20150101到20180101之间保留的成员数:
SELECT member FROM my_table WHERE timestamp = "20150101"
INTERSECT
SELECT member FROM my_table WHERE timestamp = "20180101";
在 MySQL 中实现这些逻辑集合操作的最优雅的方法是什么?
LEFT JOIN 最有可能满足您对前两个的需求,第三个是简单的 INNER JOIN。
已添加成员
SELECT t1.member
FROM my_table AS t1
LEFT JOIN my_table AS t2 ON t1.member = t2.member AND t2.timestamp = "20150101"
WHERE t1.timestamp = "20180101"
AND t2.id IS NULL -- this filters results to only those members who did not have an entry in t2
;
会员流失
应该只能交换上面的时间戳值。
使用这种通用形式:
SELECT t1.member
FROM my_table AS t1
LEFT JOIN my_table AS t2 ON t1.member = t2.member AND t2.timestamp = Y
WHERE t1.timestamp = X
AND t2.id IS NULL -- this filters results to only those members who did not have an entry in t2
;
查询基本上是获取记录在时间戳 X 时存在但在时间戳 Y 时未记录为存在的成员。如果 X > Y,那将是成员获得;如果 X < Y. 那将是成员丢失。
保留成员
SELECT t1.member
FROM my_table AS t1
INNER JOIN my_table AS t2 ON t1.member = t2.member
AND t2.timestamp = "20150101" -- This condition would be more "properly"
-- part of the WHERE clause's conditions,
-- but (unlike the LEFT JOIN queries) whether it
-- is in the ON or the WHERE will not change the results
WHERE t1.timestamp = "20180101"
;
我们需要跟踪随时间变化的集成员资格。我可以用以下简单的 table:
来解释我们的问题+-----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| timestamp | varchar(8) | NO | | NULL | |
| member | varchar(4) | NO | | NULL | |
+-----------+------------------+------+-----+---------+----------------+
SELECT*运算结果如下:
SELECT * FROM My_Table;
+----+-----------+--------+
| id | timestamp | member |
+----+-----------+--------+
| 1 | 20150101 | A |
| 2 | 20150101 | B |
| 3 | 20150101 | C |
| 4 | 20180101 | A |
| 5 | 20180101 | D |
| 6 | 20180101 | E |
+----+-----------+--------+
从逻辑上讲,我们可以使用 SET 操作 MINUS 和 INTERSECT 来了解在一段时间内添加、删除或保留了哪些成员。例如,下面的 "logical" 集合操作给出了在 20150101 和 20180101 之间添加的成员数:
SELECT member FROM my_table WHERE timestamp = "20180101"
MINUS
SELECT member FROM my_table WHERE timestamp = "20150101";
同样,下面的"logical"设置操作给出了20150101到20180101之间掉线的成员数:
SELECT member FROM my_table WHERE timestamp = "20150101"
MINUS
SELECT member FROM my_table WHERE timestamp = "20180101";
下面的"logical"集合运算给出了20150101到20180101之间保留的成员数:
SELECT member FROM my_table WHERE timestamp = "20150101"
INTERSECT
SELECT member FROM my_table WHERE timestamp = "20180101";
在 MySQL 中实现这些逻辑集合操作的最优雅的方法是什么?
LEFT JOIN 最有可能满足您对前两个的需求,第三个是简单的 INNER JOIN。
已添加成员
SELECT t1.member
FROM my_table AS t1
LEFT JOIN my_table AS t2 ON t1.member = t2.member AND t2.timestamp = "20150101"
WHERE t1.timestamp = "20180101"
AND t2.id IS NULL -- this filters results to only those members who did not have an entry in t2
;
会员流失 应该只能交换上面的时间戳值。
使用这种通用形式:
SELECT t1.member
FROM my_table AS t1
LEFT JOIN my_table AS t2 ON t1.member = t2.member AND t2.timestamp = Y
WHERE t1.timestamp = X
AND t2.id IS NULL -- this filters results to only those members who did not have an entry in t2
;
查询基本上是获取记录在时间戳 X 时存在但在时间戳 Y 时未记录为存在的成员。如果 X > Y,那将是成员获得;如果 X < Y. 那将是成员丢失。
保留成员
SELECT t1.member
FROM my_table AS t1
INNER JOIN my_table AS t2 ON t1.member = t2.member
AND t2.timestamp = "20150101" -- This condition would be more "properly"
-- part of the WHERE clause's conditions,
-- but (unlike the LEFT JOIN queries) whether it
-- is in the ON or the WHERE will not change the results
WHERE t1.timestamp = "20180101"
;