0

我们需要跟踪随时间变化的集合成员。我可以用下面的简单表格来解释我们的问题:

+-----------+------------------+------+-----+---------+----------------+
| 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 来了解在一段时间内添加、删除或保留了哪些成员。例如,以下“逻辑”集合操作给出了在 20150101 和 20180101 之间添加的成员数:

SELECT member FROM my_table WHERE timestamp = "20180101"
MINUS
SELECT member FROM my_table WHERE timestamp = "20150101";

同样,以下“逻辑”集合操作给出了在 20150101 和 20180101 之间删除的成员数:

SELECT member FROM my_table WHERE timestamp = "20150101"
MINUS
SELECT member FROM my_table WHERE timestamp = "20180101";

以下“逻辑”集合操作给出了 20150101 和 20180101 之间保留的成员数:

SELECT member FROM my_table WHERE timestamp = "20150101"
INTERSECT
SELECT member FROM my_table WHERE timestamp = "20180101";

在 MySQL 中实现这些逻辑集合操作的最优雅的方式是什么?

4

1 回答 1

1

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"
;
于 2018-05-02T17:33:28.303 回答