web-dev-qa-db-ja.com

同じテーブルからのデータの2つのサブセットを比較するクエリ?

私の問題:

私は1つのテーブル内のデータのサブセットと比較しようとしていますが、部分的に機能する2つの方法と、それを行うためのより正確な方法が必要であるという確実性があります。

ここでのアイデアは、同じシステムに関するデータセットを長期にわたって含むテーブルです。これらを比較し、特に導入または不在がある場合を確認したいと思います。簡単なテストテーブルを使って説明します。

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    |
+-----+------------+------+----------+----------+

この例では、「古い」データセットと「新しい」データセットの2つのデータセットがあります。それぞれが、ある時点で取得されたデータサンプルを反映しています。サーバー「エンタープライズ」の場合、時間とともに変化する1つのソフトウェアパッケージ(Apache)、導入された1つのソフトウェアパッケージ(Tomcat)、および存在しなくなった1つのソフトウェアパッケージ(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   |
+------------+----------+----------+----------+

私の目的にとって、上記の「NULL」セルを表示できることが重要です。ソフトウェアがシステムに追加または削除された時期を知る必要があります。明確にするために、上記の表はクエリの結果ではありません-私が探しているものを説明するためにテキストエディターを使用して修正しました。そのテーブルを作成するクエリを理解するためにあなたの助けが必要です:)

マイクラッジ:

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    |
+------------+----------+----------+----------+----------+

次の試みは、2つのビューを作成して、タグフィルターを組み合わせずに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)

これでうまくいきました。変更だけでなく、欠席も確認できましたが、まだ紹介が表示されません。そして、このためにビューを作成する必要がありました。これは、時間の経過とともにデータセットが追加されるのと同じくらい柔軟性がありません。

私の質問:

  1. 上記の「目標」セクションのNULLセルで表されるように、すべての穴が表示されることを確認するにはどうすればよいですか?
  2. 松葉杖としてのビューの作成を避けて、単一のクエリ内で実行できますか?

あなたが提供できるどんな助けでも大歓迎です。ありがとう!

6
gowenfawr

派生テーブル、つまり暗黙の一時テーブル、別名「 from句のサブクエリ 」でハックする必要があると思います。

Gocoreからの各個別(サーバー、ソフトウェア)を含む「t」と呼ぶテーブルを導出し、タグ= 'old'とタグ= 'new'で1回ずつ、gocoreに2回左結合します。

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';
9