LoginSignup
5
4

More than 5 years have passed since last update.

データが無い場合だけSELECTの結果を保存するSQL

Last updated at Posted at 2015-04-13

SELECTの実行結果を、条件に応じて別のテーブルに保存する方法を解説します。SELECTの結果を他のテーブルに保存する場合は、下記のようなINSERT分とSELECT文を合体すれば実現できます。

insert
INSERT INTO "保存先テーブル名"
(SELECT * FROM hoge );

今回は、保存先のテーブルに該当の結果が無い場合だけ、実行するようなSQLを考えてみます。主キーの設定等で別の実現方法もあるかと思いますが、ワーニングを出したくない場合には今回の方法が有効かもしれません。

実行環境

テーブル

今回は集計対象のテーブル(base)と、集計結果を保存するテーブル(ans)の2つがあると考えて下さい。

集計対象テーブル:base

スクリーンショット 2015-04-12 23.15.55 (1).png

CREATE_TABLE_BASE
/**
 * ダミーデータ1000行を作成しbaseテーブルで保存
 **/
CREATE TABLE base AS 
SELECT 
  (RANDOM()*100)::smallint AS "年齢" 
, CASE WHEN (RANDOM()*100)::smallint %2  = 1 THEN '男性' ELSE '女性' END AS "性別"
FROM generate_series( 1, 1000); 

年齢と性別の2列の構成のテーブルです。
行数は12行が表示されていますが、数万行あっても構いません。

集計結果保存テーブル:ans

スクリーンショット 2015-04-12 23.31.19 (1).png
ansテーブルには、年代、男性合計、女性合計の3列があります。年代には、集計した年齢の階級を、男女それぞれの合計人数を投入します。
今回は、年代のカラムを主キーとし、同じ年代の集計結果が投入されないようになっています。

CREATE_TABLE_ANS
CREATE TABLE ans
(
  "年代" smallint NOT NULL,
  "男性合計" bigint,
  "女性合計" bigint,
  CONSTRAINT ans_pkey PRIMARY KEY ("年代")
)
WITH (
  OIDS=FALSE
);

検証環境

PostgreSQL 9.3の環境で開発・検証をしました。

SQL

filename
INSERT INTO ans 
SELECT 
 TRUNC("年齢", -1) AS "年代" ,
 COUNT( CASE WHEN "性別"='男性' THEN 1 ELSE null END  ) AS "男性合計" ,
 COUNT( CASE WHEN "性別"='女性' THEN 1 ELSE null END  ) AS "女性合計" 
FROM base 
WHERE 
 TRUNC("年齢", -1) = 30 --30代の
GROUP BY 1 
LIMIT 1 - (SELECT COUNT(*) FROM ans WHERE "年代" = 30 );

SELECT * FROM ans WHERE "年代" = 30 ;

SQLのポイント

ポイントはLIMIT句にあります。
LIMIT句の内部のサブクエリで、挿入先のansテーブルのデータの有無を確認し、レコードが存在する場合はINSERT文がLIMIT 0 の何も返却しないSQLになります。

挿入する対象のテーブルに条件に合致するレコードが存在しない時にだけ、集計が実行されます。

5
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4