ゆるっとLIFE

ゆるく日々思ったことを徒然なるままに。プログラミング、インターネット、通信など、IT/ICTなお話がメインかも。

SQL の UNION ALL の罠

はろー。

 

とあるC#でプログラムするお仕事で、データベース(MS Access)から、

  • よく似た2つのtableから、
  • その2つのtableを合わせたデータを、
  • とあるcolumnの降順で出力しないといけなくなった。

 

学生時代から、データベース/SQL超苦手なのわけで、
その苦労を時系列順にまとめておこう・・・。

検索しても出てくるのは基本形の書き方ばかりで、
ちょっと変わったことや、その解説やサンプルには遭遇せず、苦労の連続であった。

 

さて、どうしたものかと調べていたら、
UNION ALL を使えば、同じテーブル構造のものを結合(合体)させられるらしい。

 

例:
SELECT * FROM テーブル1
UNION ALL
SELECT * FROM テーブル2
UNION ALL
SELECT * FROM テーブル3

 

なるほど、簡単そうだ。
例を参考に書いてみる。

 

SELECT * FROM テーブル1
UNION ALL
SELECT * FROM テーブル2

 

だがしかし、このSQLを実行するところでエラーになり、
さっぱりわからなくなった。

 

さらに調べていくうちに、「テーブル構造が同じ」ものでないといけないらしい

 

ということで、あらためてテーブル1、テーブル2の構造をみてみると、
全く同じようで、微妙に違うという・・・。
columnの順番が違い、さらにテーブル2の方がcolumnの数が多い

 

ダメじゃん。

 

そこで、
「SELECTで取り出すcolumnをそれぞれ同じに指定してやれば良いんじゃなかろうか?」
と考え、書き換えてみる。

 

SELECT 列名1, 列名2, 列名X, 列名4, 列名5 FROM テーブル1
UNION ALL
SELECT 列名1, 列名2, 列名X, 列名4, 列名5 FROM テーブル2

 

エラー。ダメじゃん。

そして、気づく、列名Xは、
テーブル1(およびテーブル2)からIDで参照されたテーブル3のIDに対応したカラム名
(つまり、列名Xは、テーブル1、テーブル2には存在しないカラム名だった。)

 

登場人物が増えた・・・。(テーブル3)

さらに結合と条件を書き加えることに。

ということで、INNER JOIN も調べることに・・・。(もうわかんないよ)涙

 

SELECT 列名1, 列名2, テーブル3.列名X AS 列名X, 列名4, 列名5 FROM テーブル1
INNER JOIN テーブル3 ON テーブル3 = テーブル1.ID
WHERE 列名2=●●●

UNION ALL
SELECT 列名1, 列名2, テーブル3.列名X AS 列名X, 列名4, 列名5 FROM テーブル2
INNER JOIN テーブル3 ON テーブル3 = テーブル1.ID
WHERE 列名2=●●●

 

やはりエラー
もうさっぱりわからん!やだ!(この時点でまだ構文ミスってることに気付かず。)

 

 

その日は一旦あきらめ・・・、

 

 

翌日、別の方法を模索しながら色々やっていたら、
気づいた。

明らかにミスってる。
これを修正して動けば、降順で並び替えもできるだろ?!

 

SELECT 列名1, 列名2, テーブル3.列名X AS 列名X, 列名4, 列名5 FROM テーブル1
INNER JOIN テーブル3 ON テーブル3.ID = テーブル1.ID
WHERE 列名2=●●●

UNION ALL
SELECT 列名1, 列名2, テーブル3.列名X AS 列名X, 列名4, 列名5 FROM テーブル2
INNER JOIN テーブル3 ON テーブル3.ID = テーブル2.ID
WHERE 列名2=●●●
ORDER BY 列名5 desc;

 

取り出せた!
感動!全米が泣いた

 

いろいろ間違えていたが、
「「テーブル構造が同じ」でないと UNION ALL できない」
というのクセモノだったようだ。
(SELECT * で全て取り出す場合には、その表現は合っているのだろう)

 

わかったことは、
UNION ALLは、
「column数」「データの型」「columnの順番」
が同じQuery結果 を結合させられる
ようだ。

ORDER BY は、各SELECT結果をUNIONで合体させた結果に対して、
ORDER BY するので、末尾に記述すれば良いとのこと。

 

なるほど、勉強になりました。

 

ちなみに、
UNION だけだと、重複する行は削除され、
UNION ALL だと、重複した行も含まれる、らしい。
(重複とする判定範囲は、行まるごと(各columnの値すべてが同じ場合)のようだ。)

 

時間(日)を置いて、別の視点で見ることも大切ですね。
ひらめきがある!