ラベル insert の投稿を表示しています。 すべての投稿を表示
ラベル insert の投稿を表示しています。 すべての投稿を表示

2021年7月18日日曜日

SQLite 3 insertした行の内容を取得する (returning)

概要

insert文実行時に、実際に挿入したレコード(行)の内容を確認するSQL。 「returning」構文を使用する。

以下のような状況で役に立ちそう。

  • insert~selectのようにinsertするデータを直接insert文に記載しない場合の確認。
  • insert~on conflict を使った時に実際に反映されたデータの確認。

「returning」構文はSQLite の ver 3.35.0 から利用可能。

構文


insert into table_name (
    column_name1
    , column_name2
    , column_name3 ...
)
values (
    value1
    , value2
    , value3 ...
)
returning
    column_name1
    , column_name2
    , column_name3 ...
;
                    

実行例

以下のようなサンプルテーブルにデータを新規挿入する

「product」テーブル
カラム名 データ型 制約
id integer primary key
name text not null
quantity integer default 0

sqlite> -- # 1.
sqlite> insert into product (
   ...>     id
   ...>     , name
   ...>     , quantity
   ...> )
   ...> values (
   ...>     1
   ...>     , 'tomato'
   ...>     , 100
   ...> )
   ...> returning
   ...>     id
   ...>     , name
   ...>     , quantity
   ...> ;
1|tomato|100

sqlite> -- # 2.
sqlite> select * from product;
1|tomato|100
                    
  1. returning構文を使うとinsertされたレコードが表示される
  2. テーブルにも正しく挿入されている

returning で取得するカラムに「*」を指定することもできる。


sqlite> insert into product (
   ...>     id
   ...>     , name
   ...>     , quantity
   ...> )
   ...> values (
   ...>     1
   ...>     , 'tomato'
   ...>     , 100
   ...> )
   ...> returning
   ...>     *
   ...> ;
1|tomato|100|
                    

returningで取得するカラムに別名をつけることもできる。


sqlite> .mode box
sqlite> .headers on
sqlite> insert into product (
   ...>     id
   ...>     , name
   ...>     , quantity
   ...> )
   ...> values (
   ...>     1
   ...>     , 'tomato'
   ...>     , 100
   ...> )
   ...> returning
   ...>     id as column_name1
   ...>     , name as column_name2
   ...>     , quantity as column_name3
   ...> ;
┌──────────────┬──────────────┬──────────────┐
│ column_name1 │ column_name2 │ column_name3 │
├──────────────┼──────────────┼──────────────┤
│ 1            │ tomato       │ 100          │
└──────────────┴──────────────┴──────────────┘     
                    

SQLite 3 コマンドラインツールでselectの結果を見やすくする
SQLite 3 コマンドラインツールでカラム名を表示する「.headers」について

デフォルト値が入った場合も取得できる

以下はquantityカラムに値を入れず、デフォルト値が設定された場合の例。


sqlite> insert into product (
   ...>     id
   ...>     , name
   ...> )
   ...> values (
   ...>     2
   ...>     , 'potato'
   ...> )
   ...> returning
   ...>     id
   ...>     , name
   ...>     , quantity
   ...> ;
2|potato|0
                    

利用上の制限

SQLite 3.35.5 の時点で「returning」構文に以下のような制限がある。 これは将来のバージョンで改善される可能性がある。

  • 仮想テーブルへのinsert文では使用出来ない。
  • 素のinsert文でのみ使用可能。トリガー内のinsert文では使用出来ない。
  • サブクエリでは使用出来ない。 例えば「insert~returning~」で取得したレコードをwhere句に使って 他のテーブルからデータをselectする、といったことは出来ない。
  • returning文で取得したレコードをソートすることは出来ない。
  • insert文を含むトリガーが設定されているテーブルに対し「insert~returning~」を実行しても、 トリガーが挿入した分のレコードは取得出来ない。
  • returningで取得したレコードには集計関数やwindow関数を使用できない。

参考サイト

2021年5月1日土曜日

SQLite 3 INSERT時にキーが重複していたら挿入しないようにする (do nothing)

概要

Primary keyやUNIQUE制約が重複するようなデータをinsertしようとすると、通常はエラーになる。 「on conflict ~ do nothing」構文を使えばエラーを出さずにキャンセルし、 重複していないレコードだけを挿入することが出来る。

一括でデータを登録したいけど重複行は無視したい、というような場合便利。

構文


insert into table_name (
    column1
    , column2
    , column3 ...
)
values (
    value1
    , value2
    , value3 ...
)
on conflict ( key_column1, key_column2 ...  )
do nothing
;
                    

SQLite 3 でレコードがあれば更新、なければ新規挿入する (upsert)

実行例

実行環境
  • Windows 10
  • sqlite3 (3.35.4) Command-Line Shell
サンプルテーブル(product)
id
primary key
name quantity remark
1 tomato 100
2 potato 120 bagging
3 pumpkin 50 cutted

まずはキーが重複してエラーが出る例。
「Error: UNIQUE constraint failed:~」となる。



sqlite> insert into product (
   ...>    id
   ...>    , name
   ...>    , quantity
   ...>    , remark
   ...> )
   ...> values (
   ...>    1
   ...>    , 'cassava'
   ...>    , 100
   ...>    , ''
   ...> );
Error: UNIQUE constraint failed: product.id
sqlite>
                    

「on conflict ~ do nothing 」を使うとエラーが出なくなり、 テーブルも元通りのまま。


sqlite> insert into product (
   ...>    id
   ...>    , name
   ...>    , quantity
   ...>    , remark
   ...> )
   ...> values (
   ...>    1
   ...>    , 'cassava'
   ...>    , 100
   ...>    , ''
   ...> )
   ...> on conflict (id)
   ...> do nothing
   ...> ;
sqlite> select * from product;
┌────┬─────────┬──────────┬─────────┐
│ id │  name   │ quantity │ remark  │
├────┼─────────┼──────────┼─────────┤
│ 1  │ tomato  │ 100      │         │
│ 2  │ potato  │ 120      │ bagging │
│ 3  │ pumpkin │ 50       │ cutted  │
└────┴─────────┴──────────┴─────────┘
                    

応用

「on conflict ~ do nothing」は複数のデータをinsertする際にも使うことができる。 例えば「insert~select」で他のテーブルからデータをコピーする場合、キー項目が重複していたデータを無視しつつ 重複しないデータのみをinsertすることが出来る。


insert into table_name_A (
    column1
    , column2
    , column3 ...
)
select
    column4
    , column5
    , column6 ...
from
    table_name_B
where true
on conflict ( key_column )
do nothing
;
                    

参考サイト

2021年4月17日土曜日

SQLite 3 テーブルに新規データを追加する (insert)

概要

insert文の基本的な使い方

構文

カラムを指定して挿入する場合、カラム名と挿入する値を順番に指定する


insert into table_name (
    column_name1
    , column_name2
    , column_name3 ...
)
values (
    value1
    , value2
    , value3 ...
)
                    

実行例

以下のようにサンプルテーブルにデータを新規挿入する

id
integer
name
text
quantity
integer
remark
text
1 tomato 100

insert into product
    (id, name, quantity, remark)
values
    (1, 'tomato', 100, '')
;
                    

カラム名と値の順番が対応していれば、並びが替わってもOK


insert into product
    (name, remark, quantity, id)
values
    ('tomato', '', 100, 1)
;
                    

値を入れないカラムは省略可能。
省略した場合はデフォルト値が入るかnullになる。
以下はremarkカラムを省略した例。


insert into product
    (id, name, quantity)
values
    (1, 'tomato', 100)
;
                    

構文

カラム名を省略することもできるが、その場合 最初のカラムから順番に値を指定する。


insert into sample_table
values (
    value1
    , value2
    , value3 ...
)
                    

実行例

以下のようにサンプルテーブルにデータを新規挿入する

id
integer
name
text
quantity
integer
remark
text
1 tomato 100

insert into sample_table
values 
    ( 1 , 'tomato' , 100 , '')
                    

参考サイト

2021年4月3日土曜日

SQLite 3 デフォルト値だけの行を登録する

概要

通常のinsert文ではカラムに値を指定しなかった場合デフォルト値が入る。
一行丸ごとデフォルト値にしたい場合、値に「default values」を指定すればいい。

デフォルト値が設定されていないカラムはnullになる。

利用にあたってはテーブルのスキーマを確認しておくこと。

構文


insert into table_name default values;
                    

実行例

環境
  • Windows 10
  • sqlite3 Command-Line Shell ver 3.34.1
サンプルテーブル
カラム名 データ型 デフォルト値
id integer (自動採番)
name text 'no name'
mail text 'team@example.com'
create_date text データの挿入日
update_date text (なし)

sqlite> --# 1.
sqlite> create table sample_table (
   ...>     id integer primary key autoincrement
   ...>     , name text default 'no name'
   ...>     , mail text default 'team@example.com'
   ...>     , create_date text default current_timestamp
   ...>     , update_date text
   ...> );

sqlite> --# 2.
sqlite> insert into sample_table default values;

sqlite> --# 3.
sqlite> .mode box
sqlite> .nullval (null)

sqlite> --# 4.
sqlite> select * from sample_table;
┌────┬─────────┬──────────────────┬─────────────────────┬─────────────┐
│ id │  name   │       mail       │     create_date     │ update_date │
├────┼─────────┼──────────────────┼─────────────────────┼─────────────┤
│ 1  │ no name │ team@example.com │ 2021-03-07 08:25:58 │ (null)      │
└────┴─────────┴──────────────────┴─────────────────────┴─────────────┘
                    
  1. サンプルテーブルを作成
  2. デフォルト値の行を追加
  3. selectの表示結果を見やすくする
  4. 追加した結果を確認

not null などの制約がある場合

not nullや外部キー制約に違反する場合はエラーになる。

以下はnot null制約が設定されているカラムに対し、 「insert ~ default values」を実行しようとした例。

サンプルテーブル
カラム名 データ型 デフォルト値
id integer (自動採番)
name text 'no name'
mail text 'team@example.com'
create_date text データの挿入日
update_date text not null

sqlite> create table sample_table (
   ...>     id integer primary key autoincrement
   ...>     , name text default 'no name'
   ...>     , mail text default 'team@example.com'
   ...>     , create_date text default current_timestamp
   ...>     , update_date text not null
   ...> );
sqlite> insert into sample_table default values;
Error: NOT NULL constraint failed: sample_table.update_date
                    

triggerでは使えない

trigger内では「insert ~ default values」はサポートされておらず、作成時にエラーになる。


sqlite> create trigger
   ...>    new_trigger
   ...> before insert on
   ...>    sample_table
   ...> begin
   ...>    insert into update_log default values;
   ...> end;
Error: near "default": syntax error
                    

参考サイト

2021年3月28日日曜日

SQLite 3 複数行のデータを一回のinsert文で挿入する。

実行例


insert into sample_table
	(id, name, mail)
values
	(001, 'sample001', 'sample001@example.com')
	, (002, 'sample002', 'sample002@example.com')
	, (003, 'sample003', 'sample003@example.com')
;
                    

実際使う機会はそれほど多くない。

他のテーブルのデータを反映するのであれば「insert~select」、 CSVなどのテキストデータを取り込むのであればコマンドラインツールの「.import」コマンドを使ったほうがいい。

参考サイト

2021年3月13日土曜日

SQLite3 selectの結果からinsert文を作る

概要

select文で取得した結果を別のテーブルやデータベースに挿入するためのSQLを作成する。

SQLite コマンドラインツールで「.mode insert」を使えば簡単に実現できる。


sqlite> .mode insert  
                

SQLite内でselectした結果をinsertする場合は「insert~select」構文を使えばいいので、

OracleやMySQLなどの他のデータベースにデータを移行する場合に利用する。

insert文はシンプルなので互換性の問題も起こりにくい。

実行例

実行環境
  • Windows 10 64bit
  • SQLite3 (3.34.1) Command-Line Shell

出力したinsert文を再利用する場合は"table"の部分を書き換えること。


sqlite> .mode box
sqlite> select * from user;
┌────┬────────┬────────────────────┐
│ id │  name  │        mail        │
├────┼────────┼────────────────────┤
│ 1  │ admin  │ admin@example.com  │
│ 2  │ sales1 │ sales1@example.com │
└────┴────────┴────────────────────┘
sqlite> .mode insert
sqlite> select * from user;
INSERT INTO "table" VALUES(1,'admin','admin@example.com');
INSERT INTO "table" VALUES(2,'sales1','sales1@example.com');
                

selectの件数が多ければ 「.once」 コマンドでテキストファイルに出力してしまえばいい。


sqlite> .once insert.sql
sqlite> select * from user;
sqlite> 
                

insert.sql


INSERT INTO "table" VALUES(1,'admin','admin@example.com');
INSERT INTO "table" VALUES(2,'sales1','sales1@example.com');
                

参考URL

2019年7月25日木曜日

SQLite3 Selectしたデータを他のテーブルに挿入(insert ~ select, replace ~ select)

概要

selectしたデータを使ってinsert , replaceするためのSQL。 selectとinsertを別々に実行するのではなく1文で済ませられる。 タイトルには「他のテーブルに」と入れたけど、同じテーブルでもOK。 (そんな機会はほぼないはず・・・)

以下のような機会に使う。

  • CSVファイルを一時テーブルにインポートした後、 本番テーブルに取り込む
  • マテリアライズドビューのようなものを作る
  • テーブル間でデータをコピーする

insert ~ select

selectした結果をinsertする。
selectするカラム・型は挿入するテーブルのカラム・型と揃えること。

例. 「table_02」のデータを「table_01」に全てコピーする

insert into
    table_01
select
    *
from
    table_02
;
                    
例. カラムや条件を指定してselectした結果をinsertする

insert into
    table_01 (
        column_01
        , column_02
        , column_03
    )
select
    column_05
    , column_06
    , column_07
from
    table_02
where
    column_05 = XXXX
;
                    

ユニークキーが重複している場合はエラーになるので、 必要があればあらかじめチェックしておくこと。

重複していない行のみをinsertしたい場合は以下参照のこと。
SQLite 3 INSERT時にキーが重複していたら挿入しないようにする

replace ~ select

selectした結果でreplaceする。
ユニークキーが重複している場合は置換される。

例.「table02」のデータを「table01」にマージする

replace into
    table_01
select
    *
from
    table_02
;
                    
例. カラムや条件を指定してselectした結果でreplaceする

replace into
    table_01 (
        column_01
        , column_02
        , column_03
    )
select
    column_05
    , column_06
    , column_07
from
    table_02
where
    column_05 = XXXX
;
                    

replace構文については以下を参照のこと。
SQLite3 でレコードがあれば置換、なければ新規挿入する (replace)

selectしたデータでupdateをしたい場合は以下を参照のこと。
SQLite3 Select した結果でUpdateする(update from)

外部参考サイト

2019年7月2日火曜日

SQLite3でUpsertを実行する

概要

SQLite 3 でキーか重複するレコードがあれば更新、なければ新規挿入する方法。

具体的には テーブルにレコードを新規挿入しようとして Primary key や Unique が重複するレコードが既に存在していた場合、 新規挿入をやめて update に切り替えるための構文。

以下のような処理分岐をしてくれる。

重複するレコードがある場合 既存のレコードを「更新(update)」する、もしくは何もしない(nothing)
重複するレコードがない場合 そのまま 「新規挿入(insert)」

似たような処理にreplaceがあるが、 replaceはレコード(行)を丸ごと入れ替える(delete/insert)のに対し、 upsertはカラムを指定してレコードを更新する。

公式 によると PostgreSQL の構文を利用しているとのこと。
Microsoft SQLServer や Oracle の「merge(マージ)」構文に近い使い方だが
mergeは重複の判定にUniqueカラム以外のものを指定できたりする。

実行例

「upsert」というコマンドがあるわけではなく、 on conflict文を使い キーが重複した場合の処理を指定することができる。

on conflict文は sqlite のバージョン3.24.0 から利用可能。

環境
  • Windows 10
  • sqlite3 (3.24.0) Command-Line Shell
サンプルテーブル(product)
id
primary key
autoincrement
name
not null
quantity
default 0
remark
1 tomato 100
2 potato 120
3 pumpkin 50 (Comment...)

重複していたら特定のカラムを更新する

以下は「id」カラムが重複していたら新規挿入をやめて、 別の値で「quantity」カラムを更新する例。


insert into 
    product (
        id
        , name
        , quantity
        , remark
    )
values (
        2
        , 'potato'
        , 150
        , ''
    )
on conflict(id)
do update
    set
        quantity = '200'
;
                    
結果
id
primary key
autoincrement
name
not null
quantity
default 0
remark
1 tomato 100
2 potato 200
3 pumpkin 50 (Comment...)

excluded テーブルを利用する

挿入しようとして、ユニークキーの重複エラーになった行は 「excluded」という一時テーブルに登録される。 update の際にこのexcludedを利用できる。

以下は「id」カラムが重複していたら 新規挿入をやめて、 挿入しようとした値で「quantity」カラムを更新する例


insert into
    product (
        id
        , name     
        , quantity
        , remark
    )
values (
        2
        , 'potato'
        , 150
        , ''
)
on conflict(id)
do update
    set
        quantity = excluded.quantity
;                       
                    
結果
id
primary key
autoincrement
name
not null
quantity
default 0
remark
1 tomato 100
2 potato 150
3 pumpkin 50 (Comment...)

重複していなければ、新規登録される

以下は「id」カラムが重複していないので、 そのまま新規挿入される例。


insert into
    product (
        id
        , name
        , quantity
        , remark
    )
values (
        4
        , 'potato'
        , 150
        , ''
    )
on conflict(id)
do update
    set
        quantity = '200'
;
                    
結果
id
primary key
autoincrement
name
not null
quantity
default 0
remark
1 tomato 100
2 potato 120
3 pumpkin 50 (Comment...)
4 potato 150

重複していた場合は何もしない、ということもできる

on conflictの後にdo nothingを記述すれば 重複していた場合は何もしない、という処理に出来る。


insert into
    product (
        id
        , name
        , quantity
        , remark
    )
values (
        2
        , 'potato'
        , 150
        , ''
    )
on conflict(id)
do nothing
;
                    
結果
id
primary key
autoincrement
name
not null
quantity
default 0
remark
1 tomato 100
2 potato 120
3 pumpkin 50 (Comment...)
行を丸ごと入れ替えるだけであれば replace を使う。

参考URL