質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.51%

  • SQL

    3016questions

    SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

  • PostgreSQL

    1357questions

    PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

PostgreSQL テーブル存在チェックと和集合の両立(if exists, union all)

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 5,177

poyopi

score 97

指定した名前のテーブルが存在したらunion allするというSQLを書きたく、

を参考に、下記のようなSQLを走らせてみたのですが:

SELECT * FROM(
    SELECT * FROM table1 
    WHERE EXISTS(
        SELECT relname FROM pg_class WHERE relkind='r' relname='table2'
        )
    ) tables
ORDER BY /* 略 */

"table2"がなかった場合、ないよということで怒られてしまいました:relation "table2" does not exist
そこで調べたのですが、テーブルの存在有無で、なかったときにひっかからないためには、if existsがよいという記載をDROP TABLE - PostgreSQL 8.4.4文書に見つけました。

それを受けて下記のように改めたがそれぞれで怒られてしまいます:

/* ERROR: syntax error at or near "EXSITS" */
SELECT * FROM(
    SELECT * FROM table1
    IF EXISTS table2 
        THEN UNION ALL SELECT * FROM table2
    END IF
    )tables
ORDER BY /* 略 */

/* ERROR: syntax error at or near "IF" */
SELECT * FROM(
    SELECT * FROM table1
    UNION ALL
    IF EXISTS table2 THEN
        SELECT * FROM table2
    END IF
    )tables
ORDER BY /* 略 */

文法がおかしいようであるがわかりませんでした(参考書籍SQL実践入門では索引にIFがなく、正しい文法がわからない)。検索してみたものの、IF EXISTSはDROPなどの操作で使われている例示しか探し出せず、確かに参考としたページでもDROP TALBEの際のパラメータとしてIF EXSITSを表記しています。

実現しようとしている、「指定した名前のテーブルが存在していたらUNION ALLして抽出するが、なければ無視して抽出する」を叶えるSQLについて、上記の方向性で問題なければ文法について、上記では無理であれば何を利用したらよいか方向性(CASE式など?)をご教示いただけませんでしょうか。

実際にはORMapperを使って動的SQLとして生成したものを使いますが、可能ならばプログラムにテーブル有無チェックのようなロジックを持たせるのは避けたいと思っています。


(当質問は#39274からの続きです)
遅くなりましたがやりたいことの実現ができたので備忘録を兼ねて以下に記載します。
すぐ上で

可能ならばプログラムにテーブル有無チェックのようなロジックを持たせるのは避けたいと思っています。

という夢をもっていましたが、masuda_yuyaさんにご回答いただいたとおりSQLで一挙にまかなうのは無理のようでしたので、存在チェック用のクエリを投げて、その結果存在するテーブル名をリスト(List<String>)に詰めて、そのリストをmybatisのforeachで回してUNIONという風にしました。新しく実装するのは、

  • テーブル存在チェックSQL
  • テーブル存在チェックSQLのDTO

としました。

select relname, 
case
when relname='存在チェックしたいテーブル名1' then true
when relname='存在チェックしたいテーブル名2' then true
when relname='存在チェックしたいテーブル名3' then true
when relname='存在チェックしたいテーブル名4' then true
else false
end as existTable
from pg_class where relkind='r'


ベタSQLだと上のようになりますが、チェック対象とするテーブル群はロジックでまた別のListにつめてるのでこれもmybatis上ではforeachします。このクエリの結果をうけて、Listの中にはexistTableがtrueだったもののrelnameをつめていきます(pg_classからとってきてるので余計なテーブル名も抽出されますが、case whenで名前を指定しているもの以外はtrueになりません)。あとはそのListを使って目的のSQLでUNIONを行います。

<!-- 対象のテーブル名でテーブル存在チェックをおこなう -->
    <select id="existTable" resultType="package.DTO">
    SELECT relname, 
    CASE WHEN 
    <foreach item="target" collection="targetList" separator=" WHEN "> 
    relname=#{target} THEN true 
    </foreach>
    ELSE false 
    END AS existTable 
    FROM pg_class where relkind='r'
    </select>


<!-- 存在したテーブルはUNIONする -->
    <select id="hogehoge" resultType="package.DTO">
    SELECT
        * FROM
        (
          SELECT *  FROM basetable
        <foreach item="existTable" collection="existTableList" separator=" ">
        UNION ALL SELECT * FROM ${existTable}
        </foreach>
        ) tables 
            <where>
            <!-- 適宜条件 -->
            </where>
    </select>


説明がいつにもまして雑ですが、同じことで行き詰った人の一助となれば幸いです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

>fymartymさん

私が知っている限り、select文において、存在しないテーブル名を書くと、シンタックスエラーになります。

なぜなら、パーサ処理では、テーブル名や列名が実際にデータベース上に存在するか(アクセスできるか)を判断しているからです。

処理をすっきりとさせたいという思いからの発想であれば、その思い自体はとても素晴らしいです。
ご自身でももう一つの答えは出ていると思いますが、今回のケースでは、下記のように二段階の処理にすることを、おススメします。

  1. ライブラリ表を検索し、対象のテーブルが存在するかチェックする。
  2. チェックした結果をもとに、Mapperの仕組みを利用してSQLを組み立てる。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/07/04 18:09

    ご回答ありがとうございます。
    > select文において、存在しないテーブル名を書くと、シンタックスエラーになります。
    そういうものなのですね。ありがとうございます。
    > 下記のように二段階の処理にする
    こちらの方向でやってみます。前回も関連する質問にご回答いただいたのですが、その時と同じく、実現次第質問に追記してクローズ致します。

    キャンセル

同じタグがついた質問を見る

  • SQL

    3016questions

    SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

  • PostgreSQL

    1357questions

    PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。