查询以比较同一表中的两个数据子集?

gow*_*awr 6 mysql join view

我的问题:

我正在尝试与一个表中的数据子集进行比较,并且我有两种方法可以部分工作,并且确定必须有一种更正确的方法来做到这一点。

这里的想法是一个包含关于同一系统随时间推移的数据集的表格,我想比较它们,特别是看看何时有介绍或缺席。请允许我用一个简单的测试表来演示:

mysql> select * from gocore;
+-----+------------+------+----------+----------+
| uid | server     | tag  | software | revision |
+-----+------------+------+----------+----------+
|   1 | enterprise | old  | apache   | 2.2.25   |
|   2 | enterprise | new  | apache   | 2.4.6    |
|   3 | enterprise | new  | tomcat   | 7.0.42   |
|   4 | enterprise | old  | geronimo | 2.1.7    |
+-----+------------+------+----------+----------+
Run Code Online (Sandbox Code Playgroud)

在这个例子中有两个数据集——标签“旧”数据集和标签“新”数据集。每个都反映了在某个时间点采集的数据样本。对于服务器“企业”,我们有一个随时间变化的软件包(apache)、一个引入的软件包(tomcat)和一个消失的软件包(geronimo)。

我的目标:一个可以让我总结“旧”和“新”之间状态的查询:

+------------+----------+----------+----------+
| server     | software | revision | revision |
+------------+----------+----------+----------+
| enterprise | apache   | 2.2.25   | 2.4.6    |
| enterprise | geronimo | 2.1.7    | NULL     |
| enterprise | tomcat   | NULL     | 7.0.42   |
+------------+----------+----------+----------+
Run Code Online (Sandbox Code Playgroud)

能够看到上面的“NULL”单元格对于我的目的很重要 - 我需要知道何时从系统中添加或删除了软件。需要明确的是,上面的表格不是查询的结果——是我使用文本编辑器来修复我所描述的我正在寻找的内容。我需要你的帮助来找出制作该表的查询:)

我的 Kludges:

如果我执行 LEFT JOIN 并使用 WHERE 子句来区分“旧”和“新”标签,我只会得到两个标签下都存在的条目的结果:

mysql> select old.server, old.software, old.revision, new.software, new.revision
    -> from gocore as old left join gocore as new on old.software = new.software
    -> where old.tag = 'old' and new.tag = 'new';
+------------+----------+----------+----------+----------+
| server     | software | revision | software | revision |
+------------+----------+----------+----------+----------+
| enterprise | apache   | 2.2.25   | apache   | 2.4.6    |
+------------+----------+----------+----------+----------+
Run Code Online (Sandbox Code Playgroud)

我的下一个尝试是创建两个视图,以便我可以在不将标签过滤器混入的情况下执行 JOIN:

mysql> create view gc_old as select uid,server,tag,software,revision
    -> from gocore where tag = 'old';
Query OK, 0 rows affected (0.00 sec)

mysql> create view gc_new as select uid,server,tag,software,revision
    -> from gocore where tag = 'new';
Query OK, 0 rows affected (0.00 sec)

mysql> select * from gc_old;
+-----+------------+------+----------+----------+
| uid | server     | tag  | software | revision |
+-----+------------+------+----------+----------+
|   1 | enterprise | old  | apache   | 2.2.25   |
|   4 | enterprise | old  | geronimo | 2.1.7    |
+-----+------------+------+----------+----------+
2 rows in set (0.00 sec)

mysql> select * from gc_new;
+-----+------------+------+----------+----------+
| uid | server     | tag  | software | revision |
+-----+------------+------+----------+----------+
|   2 | enterprise | new  | apache   | 2.4.6    |
|   3 | enterprise | new  | tomcat   | 7.0.42   |
+-----+------------+------+----------+----------+
2 rows in set (0.00 sec)

mysql> select old.server, old.software, old.revision, new.revision
    -> from gc_old as old left join gc_new as new
    -> on old.software = new.software;
+------------+----------+----------+----------+
| server     | software | revision | revision |
+------------+----------+----------+----------+
| enterprise | apache   | 2.2.25   | 2.4.6    |
| enterprise | geronimo | 2.1.7    | NULL     |
+------------+----------+----------+----------+
2 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

那效果更好——我现在看到的是缺席,不仅仅是变化,但我仍然没有看到介绍。我不得不为此创建视图,这让我感到不灵活,因为随着时间的推移添加数据集。

我的问题:

  1. 我怎样才能确保所有的洞都显示出来,如上面“我的目标”部分中的 NULL 单元格所示?
  2. 我可以在单个查询中完成它,避免创建视图作为拐杖吗?

非常感谢您可以提供的任何帮助。谢谢!

Mic*_*bot 9

我认为您必须使用派生表对其进行一些修改,也就是隐式临时表,也就是“ from 子句中的子查询”。

我们派生出一个表,我们将其称为 `t`,其中包含来自 gocore 的每个不同的(服务器、软件),然后左连接到 gocore 两次,一次在 tag = 'old' 上,一次在 tag = 'new' 上。

SELECT t.server, t.software, o.revision AS old_rev, n.revision AS new_rev
  FROM (SELECT DISTINCT server, software FROM gocore) t
  LEFT JOIN gocore o ON o.server = t.server AND o.software = t.software AND o.tag = 'old'
  LEFT JOIN gocore n ON n.server = t.server AND n.software = t.software AND n.tag = 'new';
Run Code Online (Sandbox Code Playgroud)

  • 完美,确实有效(在修复了一些小拼写错误之后,我进行了编辑修复)!谢谢,不仅仅是解决方案,还给了我一些关键字(派生/隐式临时表)来学习。 (2认同)