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

2026年6月29日月曜日

SQLite3 テーブルに主キーを設定する(PRIMARY KEY)

概要

SQLite3 でカラムに主キーを設定するにはいくつか方法があるので この記事ではその方法について記載する。

環境
  • Windows 11
  • SQLite3 (3.53.1) Command-Line Shell

テーブル作成時にカラムに続けて主キーを指定する

サンプルのテーブルとしてuserテーブルを作成、 id を主キーとする。

「user」テーブル
カラム名 制約
id text 主キー
not null制約
name text

このテーブルを作成するためには以下のSQLを実行する。
カラム名の後にPRIMARY KEYと記述することで、そのカラムに主キーを設定出来る。


create table user (
    id     text  primary key not null
    , name text
);
                

上記のSQLを実行すると、idカラムに主キーが設定される。
そのため、idカラムには重複する値を登録することは出来ない。

以下は、上記のテーブルにデータを登録する例。 idカラムに重複する値を登録しようするとエラーになる。


sqlite> insert into user (id, name) values ('001', 'sample_name_1');
sqlite> insert into user (id, name) values ('002', 'sample_name_2');
sqlite> insert into user (id, name) values ('001', 'sample_name_3');
Runtime error: UNIQUE constraint failed: user.id (19)                 
                
補足

上記の方法で複数カラムを主キーとする、いわゆる「複合キー」を設定しようとするとエラーになる。 複合キーを設定するには次項で説明する「テーブル作成時にPRIMARY KEY句を使用する」を参照のこと。

以下は、複合キーを設定しようとしてエラーになる例。


sqlite> create table user (
(x1...>     id     text primary key not null
(x1...>     , name text primary key
(x1...> );
Parse error: table "user" has more than one primary key
                    

テーブル作成時にPRIMARY KEY句を使用する

カラム名に続けて主キーを指定するのではなく、テーブル作成時にPRIMARY KEY句を使用して主キーを設定することも出来る。
この方法を使用することで、複数カラムを主キーとする「複合キー」を設定することが出来る。

以下は、PRIMARY KEY句を使用して主キーを設定する例。

  1. idカラムを主キーとする場合
  2. idカラムとnameカラムを複合キーとして主キーに設定する場合


-- 1.
create table user (
  id     text not null
  , name text
  , primary key (id)
);

-- 2.
create table user (
  id     text not null
  , name text not null
  , primary key ( id, name )
);
                

複合キーは複数のカラムの値の組み合わせでユニークになることを保証するため、 複合キーに設定したカラムのいずれかに重複する値があっても、他のカラムの値が異なれば登録することが出来る。

以下は、複合キーを設定したテーブルにデータを登録する例。


sqlite> create table user (
(x1...>   id text  not null
(x1...>   , name text not null
(x1...>   , primary key ( id, name )
(x1...> );
sqlite> insert into user (id, name) values ('001', 'sample_name_1');
sqlite> insert into user (id, name) values ('001', 'sample_name_2');
sqlite> insert into user (id, name) values ('001', 'sample_name_1');
Runtime error: UNIQUE constraint failed: user.id, user.name (19)
                

テーブル作成後に主キーを設定する

SQLite3 では、既存のテーブルに対して主キーを ALTER TABLE等で追加設定することは出来ない。 そのため、既存のテーブルに主キーを設定するには、以下の手順で行う必要がある。

  1. 新しいテーブルを作成する
  2. 既存のテーブルから新しいテーブルにデータをコピーする
  3. 既存のテーブルを削除する

詳しい作業手順は下記の過去記事と同じ手順になる。
結構手間がかかるので、最初のテーブル設計はきっちりやるべし。

主キーを設定するカラムには必ず NOT NULL 制約を設定する

SQLite3 では PRIMARY KEYを指定しただけでは NULLを入力することができてしまう。

以下はidカラムに主キーを設定したテーブルにNULLを登録する例。

「user」テーブル
カラム名 制約
id text 主キー
name text

sqlite> .mode box
sqlite> .nullvalue [null]
sqlite> create table user (
(x1...>   id     text primary key
(x1...>   , name text
(x1...> );
sqlite> insert into user (id, name) values (NULL, 'sample_name_1');
sqlite> insert into user (id, name) values (null, 'sample_name_2');
sqlite> select * from user;
┌────────┬───────────────┐
│   id   │     name      │
├────────┼───────────────┤
│ [null] │ sample_name_1 │
│ [null] │ sample_name_2 │
└────────┴───────────────┘
                

上記の例では、idカラムに主キーを設定しているにも関わらず、 NULLを登録することが出来てしまっている。 さらに、NULLであれば複数登録することも出来てしまっている。
そのため、主キーを設定するカラムにはNOT NULL制約を設定したほうがよい。

これは過去バージョンで主キーにNULLが登録出来てしまっていたことに起因しているらしい。 SQLite は後方互換性を重視しているため、NULLが登録できるように維持し、 修正はしない方針らしい。

また、上記の例では主キーのデータ型がtextのためこのような挙動になっているが、 integer型の主キーの場合、もうちょっと厄介な挙動をするので、 やはり、主キーを設定するカラムにはNOT NULL制約は必須という考えでいたほうが安全。

参考URL

2026年6月23日火曜日

SQLite3 指定した文字を挟んで文字列を連結する (concat_ws(separator, X, Y, ...))

概要

文字列を連結(結合)するには||演算子か関数 concat() を使用するが、 カンマやドットなどの文字を挟んで連結する場合は concat_ws()を使用する。

ExcelのTEXTJOIN()関数と似たような感覚で使える。

ws は whitespace の略…か?

構文


concat_ws(separator, X, Y, ...)
                

実行例

環境
  • Windows 11
  • SQLite3 (3.53.1) Command-Line Shell

以下はカンマを使って文字列を連結する場合。
concat()でも同じ結果が得られるが、 concat_ws()の方が簡単に書ける。


sqlite> select concat_ws(',', 'Japan', 'Tokyo', 'Shibuya');
Japan,Tokyo,Shibuya
sqlite> select concat('Japan', ',', 'Tokyo', ',', 'Shibuya');
Japan,Tokyo,Shibuya
                

テーブルのカラムを連結する例:


sqlite> .mode box
sqlite> select * from user;
┌────┬────────────┬───────────┐
│ id │ first_name │ last_name │
├────┼────────────┼───────────┤
│ 1  │ taro       │ yamada    │
│ 2  │ jiro       │ yamada    │
│ 3  │ hanako     │ suzuki    │
└────┴────────────┴───────────┘
sqlite> select
   ...>     concat_ws('.', first_name, last_name)
   ...>         as full_name
   ...> from
   ...>     user;
┌───────────────┐
│   full_name   │
├───────────────┤
│ taro.yamada   │
│ jiro.yamada   │
│ hanako.suzuki │
└───────────────┘
                

NULLを含む場合

区切り文字にNULLを指定した場合、他の引数の内容にかかわらず、結果はNULLになる。


sqlite> .nullvalue [null]
sqlite> select concat_ws(NULL, 'Japan', 'Tokyo', 'Shibuya');
[null]
                

区切り文字以外にNULLを指定した場合、NULLは無視され、余分な区切り文字が入ることもない。


sqlite> select concat_ws(',', NULL, 'Tokyo', 'Shibuya');
Tokyo,Shibuya
                

参考URL

2026年4月26日日曜日

SQLite 3 で月単位の計算をする

概要

SQLite にはデータ型として日付型がないため、日付の計算は少し特殊な書き方をする必要がある。
この記事では「月」単位の計算についてまとめる。

実行例

環境
  • Windows 10
  • sqlite Command-Line Shell ver 3.51.3
単純な日付型の加減算では計算出来ない

date()datetime()の加減算では計算出来ず、以下のような結果になってしまう。
どうやら最初の「年」の箇所だけを数値として取り出して計算しているため、このままでは月単位の計算はできない。


sqlite> select date('2026-05-01') - date('2026-03-01');
0
sqlite> select date('2025-01-31') - date('2022-12-31');
3
sqlite> select date('2026-05-01') - 1;
2025
                        
月を加算/減算する

月単位の加算/減算をする場合はdate()datetime()の引数にNNN monthsを追加する。 例えば1年後を計算したければ+1 monthsを追加する。


sqlite> select date('2026-04-01', '+1 months');
2026-05-01

sqlite> select date('2026-04-01', '-1 months');
2026-03-01

sqlite> select datetime('2026-04-01 09:00:00', '+1 months');
2026-05-01 09:00:00

sqlite> select datetime('2026-04-01 09:00:00', '-1 months');
2026-03-01 09:00:00
                        

例えばこのようなテーブルの各行の1か月前、1か月後を計算するには以下のようなSQLになる。

user_table
user_name expiration_date
hoge1 2026-04-15
hoge2 2026-12-31
hoge3 2024-02-29

select
    user_name
    , expiration_date
    , date(expiration_date, '+1 months') as next_month
    , date(expiration_date, '-1 months') as prev_month
from
    user_table
;
                        
結果
user_name expiration_date next_month prev_month
hoge1 2026-04-15 2026-05-15 2026-03-15
hoge2 2026-05-31 2026-07-01 2026-05-01
hoge3 2024-02-29 2024-03-29 2024-01-29

5月31日に +1か月 した場合、6月31日は存在しないため、オーバーフローして7月1日が返されるっぽい。
1か月前も同じような理屈になり、4月30日が返されるわけではないので注意が必要。

2つの日付間の月数を計算する

大きく分けて2パターン。

1つ目は、strftime()関数を使って年と月の部分を取り出して計算する方法。
2つ目は、julianday()関数を使って日数に変換してから月数に変換する方法。

1つ目の方法は、単純に年と月の部分を取り出して計算する方法。
年部分の差に12(か月)をかけ、月の差を足せばいい。


sqlite> select
   ...>     ( strftime('%Y', '2026-01-05') - strftime('%Y', '2025-12-30') ) * 12
   ...>     + ( strftime('%m', '2026-01-05') - strftime('%m', '2025-12-30') )
   ...> ;
1

                        

ただし、この方法は単純に年の部分だけを取り出して計算するため、日数が考慮されない。
例えば上記のSQLでは、2026年1月5日と2025年12月30日の差は1か月と計算されるが、実際には6日の差しかない。

2つ目の方法は、日付を日数に変換してから月数に変換する方法。
例えば以下のようなSQLになる。


sqlite> select (julianday('2026-01-05') - julianday('2025-12-30')) / 30;
0.2
                        

この方法では、日付を日数に変換してから月数に変換するため、日数が考慮される。
例えば上記のSQLでは、2026年1月5日と2025年12月30日の年数の差は0.2か月と計算される。 (厳密に31日の月や2月の日数を計算しようとするとさすがに面倒なので、ここでは1か月=30日で計算している)
必要に応じて小数点以下を切り捨てるなどの処理を行うと良い。


sqlite> select cast((julianday('2026-01-05') - julianday('2025-12-30')) / 30 as int);
0
                        

参考URL

2026年4月18日土曜日

SQLite 3 で年数単位の計算をする

概要

SQLite にはデータ型として日付型がないため、日付の計算は少し特殊な書き方をする必要がある。
この記事では「年」単位の計算についてまとめる。

実行例

環境
  • Windows 10
  • sqlite Command-Line Shell ver 3.51.3
単純な日付型の加減算では計算出来ない

date()datetime()の加減算では計算出来ず、以下のような結果になってしまう。
どうやら最初の「年」の箇所だけを数値として取り出して計算しているらしいが、正直モヤっとする。


sqlite> select date('2026-05-01') - date('2026-03-01');
0
sqlite> select date('2025-01-31') - date('2022-12-31');
3
sqlite> select date('2026-05-01') - 1;
2025
                        
年を加算/減算する

上記の式で納得できるのであれば、それでOK。

ただ、コードの保守性や引継ぎを考えると 「ここは年の計算をしている」ことがコードからわかることがベスト。

年単位の加算/減算をする場合はdate()datetime()の引数にNNN yearsを追加する。 例えば1年後を計算したければ+1 yearsを追加する。


sqlite> select date('2026-04-01', '+1 years');
2027-04-01

sqlite> select date('2026-04-01', '-1 years');
2025-04-01

sqlite> select datetime('2026-04-01 09:00:00', '+1 years');
2027-04-01 09:00:00

sqlite> select datetime('2026-04-01 09:00:00', '-1 years');
2025-04-01 09:00:00
                        

例えばこのようなテーブルの各行の1年後、1年前を計算するには以下のようなSQLになる。

user_table
user_name expiration_date
hoge1 2026-04-15
hoge2 2026-12-31
hoge3 2024-02-29

select
    user_name
    , expiration_date
    , date(expiration_date, '+1 years') as next_year
    , date(expiration_date, '-1 years') as prev_year
from
    user_table
;
                        
結果
user_name expiration_date next_year prev_year
hoge1 2026-04-15 2027-04-15 2025-04-15
hoge2 2026-12-31 2027-12-31 2025-12-31
hoge3 2024-02-29 2023-03-01 2025-03-01

うるう年の2月29日に年単位の加算・減算をした結果、 その年がうるう年でない場合は2月28日ではなく 3月1日になるので注意すること。

2つの日付間の年数を計算する

大きく分けて2パターン。

1つ目は、strftime()関数を使って年の部分だけを取り出して計算する方法。
2つ目は、julianday()関数を使って日数に変換してから年数に変換する方法。

1つ目の方法は、単純に年の部分だけを取り出して計算する方法。
例えば以下のようなSQLになる。


sqlite> select strftime('%Y', '2026-05-01') - strftime('%Y', '2025-11-01') as span_year;
1
                        

ただし、この方法は単純に年の部分だけを取り出して計算するため、月や日が考慮されない。
例えば上記のSQLでは、2026年5月1日と2025年11月1日の年数の差は1年と計算されるが、実際には6ヶ月の差しかない。

2つ目の方法は、日付を日数に変換してから年数に変換する方法。
例えば以下のようなSQLになる。


sqlite> select (julianday('2026-05-01') - julianday('2026-03-01')) / 365.25;
0.167008898015058
                        

この方法では、日付を日数に変換してから年数に変換するため、月や日が考慮される。
例えば上記のSQLでは、2026年5月1日と2026年3月1日の年数の差は0.16年と計算される。 (厳密にうるう年を計算しようと思うと大変なのでここでは0.25日を使う。)
必要に応じて小数点以下を切り捨てるなどの処理を行うと良い。


sqlite> select cast((julianday('2026-05-01') - julianday('2026-03-01')) / 365.25 as int);
0
sqlite> select cast((julianday('2026-05-31') - julianday('2025-04-30')) / 365.25 as int);
1
                        

参考URL

2026年3月28日土曜日

SQLite 3 指定した日付の年・月・日 部分をを取得する(strftime())

概要

日付から年・月・日を個別に取得するには、strftime()関数を使用する。

実行例

環境
  • Windows 11
  • sqlite Command-Line Shell ver 3.51.3
年を所得する。

年を取得するにはstrftime('%Y', <日付>)を使用する


sqlite> select strftime('%Y', '2026-01-31');
2026
                        
月を取得する

月を取得するにはstrftime('%m', <日付>)を使用する


sqlite> select strftime('%m', '2026-01-31');
01
                        
日を取得する

日を取得するにはstrftime('%d', <日付>)を使用する


sqlite> select strftime('%d', '2026-01-31');
31
                        

参考URL

2026年3月21日土曜日

SQLite 3 .mode で幅広文字の表示が改善された

概要

コマンドラインツールには select 文の結果表示モードを変更する .mode コマンドがある。

今までだと、このコマンドで指定できるモードのうち boxcolumn では 幅広の文字を表示しようとすると体裁が崩れてしまっていた。

ver 3.51.0 でこれが改善され、日本語のひらがなや漢字でも体裁が崩れることなく表示されるようになった。

構文

改善された表示モードは以下の通り。


.mode box
.mode column
.mode markdown
.mode qbox
.mode table
                    

実行例

まずは古いバージョンでの見え方。

環境
  • Windows 11
  • SQLite3 Command-Line Shell ver 3.49.0

sqlite> .version
SQLite 3.49.0 2025-02-06 11:55:18 4a7dd425dc2a0e5082a9049c9b4a9d4f199a71583d014c24b4cfe276c5a77cde
zlib version 1.3
msvc-1939 (64-bit)

sqlite> create table user (id, name);
sqlite> insert into user values ('0001', 'ほげほげ');
sqlite> select * from user;
0001|ほげほげ

sqlite> .mode box
sqlite> select * from user;
┌──────┬──────┐
│  id  │ name │
├──────┼──────┤
│ 0001 │ ほげ │
└──────┴──────┘

sqlite> .mode column
sqlite> select * from user;
id    name
----  ----
0001  ほげ

sqlite> .mode markdown
sqlite> select * from user;
|  id  | name |
|------|------|
| 0001 | ほげ |

sqlite> .mode qbox
sqlite> select * from user;
┌────────┬────────┐
│   id   │  name  │
├────────┼────────┤
│ '0001' │ 'ほげほげ'  │
└────────┴────────┘

sqlite> .mode table
sqlite> select * from user;
+------+------+
|  id  | name |
+------+------+
| 0001 | ほげ |
+------+------+
                        

上記の例では、「name」カラムに「ほげほげ」というデータが入っているが、 表示モードを切り替えることで体裁が崩れ、データが欠けてしまっていることがわかる。

これが ver 3.51.0 以降は改善され、表示されるようになる。

環境
  • Windows 11 64bit
  • SQLite Command-Line Shell ver 3.51.3

sqlite> .version
SQLite 3.51.3 2026-03-13 10:38:09 737ae4a34738ffa0c3ff7f9bb18df914dd1cad163f28fd6b6e114a344fe6d618
zlib version 1.3
msvc-1939 (64-bit)

sqlite> create table user (id, name);
sqlite> insert into user values ('0001', 'ほげほげ');
sqlite> select * from user;
0001|ほげほげ

sqlite> .mode box
sqlite> select * from user;
┌──────┬──────────┐
│  id  │   name   │
├──────┼──────────┤
│ 0001 │ ほげほげ │
└──────┴──────────┘

sqlite> .mode column
sqlite> select * from user;
id    name
----  --------
0001  ほげほげ

sqlite> .mode qbox
sqlite> select * from user;
┌────────┬────────────┐
│   id   │    name    │
├────────┼────────────┤
│ '0001' │ 'ほげほげ' │
└────────┴────────────┘

sqlite> .mode markdown
sqlite> select * from user;
|  id  |   name   |
|------|----------|
| 0001 | ほげほげ |


sqlite> .mode table
sqlite> select * from user;
+------+----------+
|  id  |   name   |
+------+----------+
| 0001 | ほげほげ |
+------+----------+
                        

参考URL

2026年3月15日日曜日

SQLite3 SQL実行にかかった時間を計測する (.timer)

概要

SQLite3 で SQL を実行した際、実行にかかった時間を計測するためのコマンド。

計測出来るのは SQL のみで、コマンドラインツールのコマンドの実行時間は計測出来ない。

構文

時間計測を有効化する「on」/ 無効化する「off」
出力される時間の単位は「秒」。


.timer on
.timer off
                    

実行例

環境
  • Windows 11
  • SQLite Command-Line Shell ver 3.51.3

時間計測を「on」にしてSQLを実行する


c:\temp> rem  # 1
c:\temp> sqlite3 sample.db

sqlite> -- # 2
sqlite> .timer on

sqlite> -- # 3
sqlite> select * from user;
...
Run Time: real 4.729 user 0.312500 sys 1.078125
                        
  1. コマンドラインツールで「sample.db」というsqliteデータベースを開く
  2. 時間計測を「on」にする
  3. SQLを実行すると、SQLの実行結果の後に計測結果が秒単位で出力される

各項目の意味は以下の表の通りで、これはUNIXの timeコマンドの結果と同等の内容と思われる。 (SQLite3 公式サイトに正式な説明が載っていないので推測)

種類 意味
real 実際に経過した時間。
I/O待ちや他のプロセスの影響などクエリの開始から終了までの時間になる。 コマンドラインツール上であれば、select の結果をディスプレイに出力するのにかかった時間も含まれる。
user CPUが使われた時間。
実行する SQLの解析、テーブルのJOIN、ソート計算や関数の実行にかかった時間。 SQL 文の品質を確認したいならこの時間を確認すればよさそう。
sys OSが処理した時間。
ファイルの読み書きの時間が含まれる。 ケースに寄りけりだが、SQLite3 ではそこまで重要視する時間ではないかも。

一般的に real ≧ user + sys となる想定

時間計測を止めるには以下のようにコマンドを実行する


sqlite> .timer off
                        

参考URL

2026年2月1日日曜日

SQLite3 文字列を連結する (concat(X,Y,...))

概要

文字列を連結(結合)するには||演算子か 関数concat()を使用する。

構文


X || Y || ...
concat(X,Y,...)
                

実行例

環境
  • Windows 11
  • SQLite3 (3.53.1) Command-Line Shell
単純に文字列を連結する例:

sqlite> select 'taro' || '.' || 'yamada';
taro.yamada
sqlite> select concat('taro','.','yamada');
taro.yamada
                
テーブルのカラムを連結する例:

sqlite> select * from user;
┌────┬────────────┬───────────┐
│ id │ first_name │ last_name │
├────┼────────────┼───────────┤
│ 1  │ taro       │ yamada    │
│ 2  │ jiro       │ yamada    │
│ 3  │ hanako     │ suzuki    │
└────┴────────────┴───────────┘
sqlite> .mode box
sqlite> select
   ...>     first_name || '.' || last_name
   ...>         as full_name
   ...> from
   ...>     user;
┌───────────────┐
│   full_name   │
├───────────────┤
│ taro.yamada   │
│ jiro.yamada   │
│ hanako.suzuki │
└───────────────┘

sqlite> select
   ...>     concat (first_name, '.', last_name)
   ...>         as full_name
   ...> from
   ...>     user;
┌───────────────┐
│   full_name   │
├───────────────┤
│ taro.yamada   │
│ jiro.yamada   │
│ hanako.suzuki │
└───────────────┘
                

NULLを含む場合

||演算子の対象にNULLが含まれる場合、結果もNULLになる:

sqlite> .nullvalue [null]
sqlite> select 'taro' || NULL ;
┌────────────────┐
│ 'taro' || NULL │
├────────────────┤
│ [null]         │
└────────────────┘
                
concat()の引数にNULLが含まれる場合、空文字として扱われる:

sqlite> .nullvalue [null]
sqlite> select concat('taro', NULL );
┌───────────────────────┐
│ concat('taro', NULL ) │
├───────────────────────┤
│ taro                  │
└───────────────────────┘
                

参考URL

2025年12月21日日曜日

SQLite3 エラーが起きた時に処理をキャンセルする (.bail)

概要

SQLite3のコマンドラインツールを使用している際、 一連の処理でエラーになった場合、 .bailコマンドを設定しておくことで その後の処理をキャンセルすることができる。

SQLiteコマンドラインツールを起動する際に -bailオプションを指定することでも 同様の効果を得ることができる。

これにより、連鎖的にエラーが発生したり、意味のない処理が動くことを止めることができる。

構文

コマンドラインツール起動中にBail機能をON/OFF にする。(デフォルトはOFF)


.bail on
.bail off
                

コマンドライン起動時にBail機能をON にする。(デフォルトはOFF)


c:\temp> sqlite3 -bail
                

実行例

環境
  • Windows 10 64bit
  • SQLite Command-Line Shell ver 3.50.2

.bailはCLIでコマンドを手入力する作業ではあまり恩恵がない。(と思う)
外部のSQLファイルを読み込んだり、シェルのコマンドラインからSQLを渡したときに効果を発揮する。

.bailがOFFのままの場合

以下のようなSQLファイルを準備する。

sample_01.sql

-- # 1
.bail off

-- # 2
create table user_01 (id, name);
create tbl user_02 (id, name);
create table user_03 (id, name);
                    
  1. bailをOFFにする
  2. create table文を3つ実行する。
    ただし、2つ目のSQL構文に誤りがあるのでエラーが発生するようになっている。

準備したSQLファイルをSQLite3のコマンドラインツールから読み込んで テーブル一覧を表示してみる。


.read ./sample_01.sql
.tables
                    

実行結果


sqlite> .read ./sample_01.sql
Parse error near line 6: near "tbl": syntax error
  create tbl user_02 (id, name);
         ^--- error here
sqlite> .tables
user_01  user_03
                    

2つ目のSQLが失敗し、エラーになっている。 1つ目のSQLと3つ目のSQLは成功し、 テーブルが2つ作成されていることがわかる。

.bailをONにした場合

以下のようなSQLファイルを準備する。

sample_02.sql

-- # 1
.bail on

-- # 2
create table user_01 (id, name);
create tbl user_02 (id, name);
create table user_03 (id, name);
                    
  1. bailをONにする
  2. create table文を3つ実行する。
    2つ目のSQL構文に誤りがあるのでエラーになるようになっている。

準備したSQLファイルをSQLite3のコマンドラインツールから読み込む。


.read ./sample_02.sql
.tables
                    

実行結果


sqlite> .read ./sample_02.sql
Parse error near line 6: near "tbl": syntax error
  create tbl user_02 (id, name);
         ^--- error here
sqlite> .tables
user_01
                    

.tablesを実行すると、2つ目のSQLが失敗し、 3つ目のSQLで作成されるはずだったuser_03テーブルが 作成されていないことがわかる。

よって2つ目でSQLが失敗した後、以降の処理がキャンセルされていることがわかる。

コマンドラインツールから手で入力する場合

以下のような実行の仕方では .bailは意味がない。


sqlite> .bail on
sqlite> create table user_01 (id, name);
sqlite> create tbl user_02 (id, name);
Parse error: near "tbl": syntax error
  create tbl user_02 (id, name);
         ^--- error here
sqlite> create table user_03 (id, name);
sqlite> .tables
user_01  user_03
                    

以下のように一度に複数のSQLを実行する場合であれば、 途中で発生したエラー以降はキャンセルされる。

(右スクロールしてください →)


sqlite> .bail on
sqlite> create table user_01 (id, name); create tbl user_02 (id, name); create table user_03 (id, name);
Parse error: near "tbl": syntax error
  create tbl user_02 (id, name); create table user_03 (id, name);
         ^--- error here
sqlite> .tables
user_01
                    

参考URL

2025年7月13日日曜日

SQLite 3 文字列から特定の文字列があるかを確認する、 特定の文字列が何文字目から始まるかを調べる。(instr())

概要

isstr() を使うと ある文字列の中に含まれる指定した文字列の開始位置を取得できる。
文字列が含まれていない場合、関数は0 を返す。

構文


instr(str1, str2)
                
str1
調査対象の文字列
str2
str1に含まれているであろう文字列

実行例1

環境
  • Windows 10
  • SQLite ver 3.50.1

sqlite> --# 1.                    
sqlite> select instr('sample@example.com', 'hoge');
0
sqlite> --# 2.
sqlite> select instr('sample@example.com', 'sample');
1
sqlite> --# 3.
sqlite> select instr('sample@example.com', 'example');
8
sqlite> --# 4.
sqlite> select instr('sample@example.com', 'am');
2
sqlite> --# 5.
sqlite> .nullvalue [null]
sqlite> select instr(NULL, 'example');
[null]
sqlite> select instr('sample@example.com', NULL);
[null]
sqlite> select instr(NULL, NULL);
[null]
                
  1. 対象の文字列が含まれていない場合は 0 を返す
  2. 先頭で文字が見つかった場合は 1 となる
  3. 見つかった文字列の開始位置を返す
  4. 複数個所に検索文字列がある場合、最初に見つかった文字列の位置を返す
  5. 引数のどちらかがNULLの場合、 NULLを返す。

参考URL

2024年3月24日日曜日

SQLite 3 二つの値を比較し同じ場合NULLを返す(nullif())

概要

nullif()は引数に与えられた2つの値を比較し、 同じだった場合null、違った場合第一引数を返す。
iif()の亜種のような関数。

構文


nullif(value1, value2)
                
value1
二つの引数の値が異なる場合、この引数が返される。
value2
value1 と比較する値

実行例1

環境
  • Windows 10
  • SQLite ver 3.45.1

sqlite> .nullvalue [null]
sqlite> select nullif(1, 1);
[null]
sqlite> select nullif(1, 0);
1
sqlite> select nullif('sample1', 'sample1');
[null]
sqlite> select nullif('sample1', 'sample2');
sample1
sqlite> select nullif('1', 1);
1
sqlite> select nullif(true, true);
[null]
sqlite> select nullif(true, false);
1
                

参考URL

2024年3月2日土曜日

SQLite 3 NULLの場合、別の値を返す(ifnull())

概要

値がNULLかどうかを判定して、NULLだった場合別の値を返すようにするには ifnull()関数を使う。 ifnull()はOracleのNVL()に相当する機能。

構文


ifnull(value1, value2)
                
value1
NULLかどうかを判定する対象。この値がNULLでなければ関数はこの値をそのまま返す。
value2
value1がNULLだった場合、この関数はこの値を返す。

実行例1

環境
  • Windows 10
  • SQLite ver 3.45.1

sqlite> .mode box
sqlite> -- 1.
sqlite> select ifnull(null, 'sample1') as result;
┌─────────┐
│ result  │
├─────────┤
│ sample1 │
└─────────┘

sqlite> -- 2.
sqlite> select ifnull(0, 'sample2') as result;
┌────────┐
│ result │
├────────┤
│ 0      │
└────────┘
sqlite> select ifnull('not null', 'sample3') as result;
┌──────────┐
│  result  │
├──────────┤
│ not null │
└──────────┘

sqlite> -- 3.
sqlite> .nullvalue [null]
sqlite> select ifnull(null, null) as result;
┌────────┐
│ result │
├────────┤
│ [null] │
└────────┘

                
  1. 第一引数がnullだった場合、第二引数の値を返す。
  2. 第一引数がnullでなければ、第一引数をそのまま返す。
  3. 第一引数・第二引数ともにnullだった場合、nullを返す。

実行例2

users
id last_login created_at
0001 2024-02-01 2024-01-31
0002 2024-02-01
0003 2024-02-03

そのまま出力。


select
    id
    , last_login
    , created_at
from
    users
;
                    
結果
id last_login created_at
0001 2024-02-01 2024-01-31
0002 2024-02-01
0003 2024-02-03

last_login がNULLだった場合、「not logged in」を表示する。


select
    id
    , ifnull(last_login, 'not logged in') as last_login
from
    users
;
                    
結果
id last_login
0001 2024-02-01
0002 not logged in
0003 not logged in

last_login がNULLだった場合、created_at を換わりに取得する。


select
    id
    , ifnull(last_login, created_at) as last_login
from
    users
;
                    
結果
id last_login
0001 2024-02-01
0002 2024-02-01
0003 2024-02-03

参考URL

2024年2月5日月曜日

SQLite 3 コマンドラインツール起動時に読み取り専用でデータベースを開く (-readonly)

概要

SQLiteにはGRANTやREVOKEといった権限を操作するコマンドはなく、 ユーザやアクセス権限はOSのファイルアクセス管理に準ずる。

ただし、プログラミング言語用のライブラリやコマンドラインツールには データベースファイルを読み取り専用で開く手段が準備されていることがある。

このページでは、コマンドプロンプトやbashといったシェルから SQLite 3 のデータベースファイルを読み取り専用で開く方法を記載しておく。

コマンド

SQLite 3 のコマンドのオプションに「-readonly」を指定してデータベースを開くことで 読み取り専用で開くことが出来る。
読み取り専用で開くとinsert や update 実行時にエラーになる。


sqlite3 -readonly DB_NAME
                

実行例

環境
  • Windows 10 64bit
  • SQLite3 (3.43.1) Command-Line Shell

C:\temp>rem # 1.
C:\temp>sqlite3 -readonly test.db
SQLite version 3.45.1 2024-01-30 16:01:20 (UTF-16 console I/O)
Enter ".help" for usage hints.

sqlite> -- # 2.
sqlite> create table test_table (id, name);
Runtime error: attempt to write a readonly database (8)
sqlite>
                
  • 読み取り専用でtest.dbを開く
  • create文を実行しようとするとエラーになるのがわかる

SQLite 3 のコマンドラインツールを起動した後でも 「.open」コマンドを使用して読み取り専用でデータベースに繋ぎなおすことができる。

参考URL

2023年12月23日土曜日

SQLite3 指定した範囲からランダム値を取得する(random())

概要

SQLite3でランダム値を取得するにはrandom()関数を使用する。
範囲を指定するのであれば、指定したい範囲の「間隔」で割って、指定したい範囲の「最小値」を足せばいい。

構文


select abs(random()) % RANGE + MIN
                

実行例

指定した範囲内からランダム値を取得したい場合は剰余(割り算の余り)を使う。
例えば 0~4 の範囲からランダムに値を取得したい場合は 範囲 0,1,2,3,4 の個数 5 で割った余りを使う。


sqlite> select abs(random()) % 5;
1
sqlite> select abs(random()) % 5;
3
sqlite> select abs(random()) % 5;
3
sqlite> select abs(random()) % 5;
4
sqlite> select abs(random()) % 5;
2
sqlite> select abs(random()) % 5;
0
sqlite> select abs(random()) % 5;
2
                

1~5 の範囲からランダムに値を取得したい場合はこれに+1してやればいい。


sqlite> select abs(random()) % 5 + 1;
5
sqlite> select abs(random()) % 5 + 1;
1
sqlite> select abs(random()) % 5 + 1;
4
sqlite> select abs(random()) % 5 + 1;
1
sqlite> select abs(random()) % 5 + 1;
5
sqlite> select abs(random()) % 5 + 1;
2
sqlite> select abs(random()) % 5 + 1;
3
                

参考URL

2023年12月18日月曜日

SQLite3 ランダム値を取得する(random())

概要

SQLite3でランダム値を取得するにはrandom()関数を使用する。

構文


random()
                

-9223372036854775808 から 9223372036854775807 までの間の数字を一つランダムに取得する。

実行例


sqlite> select random();
3156263457218046093
sqlite> select random();
-6586383623159055896
sqlite> select random();
1694675256990323389
sqlite> select random();
-3966622455784875739
                

マイナスが不要であればabs()関数を使って 絶対値にしてやればいい。


sqlite> select abs(random());
6506298542183177295
sqlite> select abs(random());
5614770480249323342
sqlite> select abs(random());
4451325482105913098
sqlite> select abs(random());
8599032043310149984
                

参考URL

2023年12月8日金曜日

SQLite3 文字列を置換して更新する (update, replace())

概要

SQLite3 に登録されているデータの文字列を置換したい場合は、 updatereplace()を組み合わせればいい。

構文


update table_name
    set
        column_name = replace(column_name, search_string, replace_string)
                

実行例

sample_tableのurlカラムに登録されているurlの「http://」を「https://」に置換する。

sample_table(実行前)
url access_date
http://sfnovicenotes.blogspot.com/ 2023-12-09
http://sfnovicenotes.blogspot.com/p/sqlite3-select.html 2023-12-01

update sample_table
    set
        url = replace(url, 'http://', 'https://')
;
                
sample_table(実行後)
url access_date
https://sfnovicenotes.blogspot.com/ 2023-12-09
https://sfnovicenotes.blogspot.com/p/sqlite3-select.html 2023-12-01

参考URL

2023年9月24日日曜日

SQLite3 行(ROW)を繋げてJSONオブジェクトを作成する (json_group_object())

概要

SQL結果の行(row)を繋げてJSONオブジェクトを作成するには json_group_objectを使用する。

SQL結果の列(column)を繋げてJSONを作成するには json_arrayjson_objectを使用する。

構文


json_group_object(name, value)
                
name
連想配列のキー
value
連想配列の値

環境

  • Windows 10 64bit
  • SQLite3 (3.43.1) Command-Line Shell

実行例

sample
name quantity
tomato 100
potato 120
pumpkin 50

sqlite> .mode box
sqlite> select json_group_object('name', name) from test;
┌────────────────────────────────────────────────────┐
│          json_group_object('name', name)           │
├────────────────────────────────────────────────────┤
│ {"name":"tomato","name":"potato","name":"pumpkin"} │
└────────────────────────────────────────────────────┘
sqlite> select json_group_object(name, quantity) from test;
┌──────────────────────────────────────────┐
│    json_group_object(name, quantity)     │
├──────────────────────────────────────────┤
│ {"tomato":100,"potato":120,"pumpkin":50} │
└──────────────────────────────────────────┘

                

参考URL

2023年9月9日土曜日

SQLite3 行(ROW)を繋げてJSON配列を作成する (json_group_array())

概要

SQL結果の行(row)を繋げてJSONを作成するには json_group_arrayを使用する。

SQL結果の列(column)を繋げてJSONを作成するには json_arrayjson_objectを使用する。

構文


json_group_array(column_name)
                

環境

  • Windows 10 64bit
  • SQLite3 (3.41.2) Command-Line Shell

実行例

sample
name quantity
tomato 100
potato 120
pumpkin 50

sqlite> .mode box
sqlite> select json_group_array(name) from test;
┌───────────────────────────────┐
│    json_group_array(name)     │
├───────────────────────────────┤
│ ["tomato","potato","pumpkin"] │
└───────────────────────────────┘
sqlite> select json_group_array(quantity) from test;
┌────────────────────────────┐
│ json_group_array(quantity) │
├────────────────────────────┤
│ [100,120,50]               │
└────────────────────────────┘
                

参考URL

2023年7月29日土曜日

SQLite3 2つのJSONをマージする(json_patch())

概要

json_patch()を使用すると 2つのJSONオブジェクトをマージ(統合)することが出来る。

構文


json_patch(JSON_OBJECT1, JSON_OBJECT2)
                
JSON_OBJECT1
元のJSONオブジェクト
JSON_OBJECT2
JSON_OBJECT1に統合するJSONオブジェクト

実行例

環境
  • Windows 10 64bit
  • SQLite3 (3.41.2) Command-Line Shell
基本的な使い方

sqlite> .nullvalue [null]

sqlite> -- # 1.
sqlite> select json_patch('{"a":100, "b":200, "c":300}', '{"c":303, "d":400}');
{"a":100,"b":200,"c":303,"d":400}
sqlite> select json_patch('{"a":100, "b":200, "c":300}', '{"d":400, "e":500}');
{"a":100,"b":200,"c":300,"d":400,"e":500}
sqlite> select json_patch('{"a":100, "b":200, "c":300}', '{"d":400}');
{"a":100,"b":200,"c":300,"d":400}

sqlite> -- # 2.
sqlite> select json_patch('{"a":100, "b":200, "c":300}', '{"b":null}');
{"a":100,"c":300}
sqlite> select json_patch('{"a":100, "b":200, "c":300}', null);
[null]

sqlite> -- # 3.
sqlite> select json_patch(
   ...>         '{
   ...>             "a":{
   ...>                 "b":200,
   ...>                 "c":300
   ...>             }
   ...>         }',
   ...>         '{
   ...>             "a":{
   ...>                 "b":202,
   ...>                 "c":null,
   ...>                 "d":400
   ...>             }
   ...>         }'
   ...>     );
{"a":{"b":202,"d":400}}

                    
  1. 連想配列のキーを基準に1つ目のJSONに対しの2つ目のJSONをマージする
  2. nullを指定するとキーに一致する要素は削除される
  3. 階層構造も統合される
第1引数と第2引数が連想配列でない場合 マージされない

sqlite> -- # 1.
sqlite> select json_patch(1, '{"a":100, "b":200}');
{"a":100,"b":200}
sqlite> select json_patch(true, '{"a":100, "b":200}');
{"a":100,"b":200}
sqlite> select json_patch('[0, 1, 2, 3]', '{"a":100, "b":200}');
{"a":100,"b":200}

sqlite> -- # 2.
sqlite> select json_patch('{"a":100, "b":200}', '[0,1]');
[0,1]
sqlite> select json_patch('{"a":100, "b":200}', 1);
1
sqlite> select json_patch('{"a":100, "b":200}', true);
1
sqlite> select json_patch('[0,1,2,3]', '[4,5]');
[4,5]

sqlite> -- # 3.
sqlite> select json_patch('test', 'test');
Runtime error: malformed JSON
                    
  1. 第1引数が連想配列でない場合、第2引数で全て置換される
  2. 第2引数が連想配列でない場合、第2引数で全て置換される
  3. 第1引数がJSONに変換出来ない場合、エラーとなる

参考URL

2023年7月23日日曜日

SQLite3 JSONの要素を削除する(json_remove())

概要

SQLiteでJSONオブジェクトの要素を削除するには json_removeを使用する。

構文


json_remove(JSON_OBJECT, JSON_PATH, JSON_PATH ...)
                
JSON_OBJECT
対象のJSON文字列、もしくはJSONオブジェクト
JSON_PATH
削除する要素のJSON Path。複数指定可能。

実行例

環境
  • Windows 10 64bit
  • SQLite3 (3.41.2) Command-Line Shell
基本的な使い方

sqlite> .log stderr
sqlite> .nullvalue [null]

sqlite> -- # 1.
sqlite> select json_remove('[0,1,2,3,4]', '$[0]');
[1,2,3,4]
sqlite> select json_remove('[0,1,2,3,4]', '$[#-1]');
[0,1,2,3]
sqlite> select json_remove('{"a":10, "b":20}', '$.a');
{"b":20}

sqlite> -- # 2.
sqlite> select json_remove('{"a":10, "b":[0, 1, 2]}', '$.b');
{"a":10}

sqlite> -- # 3.
sqlite> select json_remove('[0,1,2,3,4]', '$');
[null]

sqlite> -- # 4.
sqlite> select json_remove('[1]', '$[0]');
[]
sqlite> select json_remove('{"a":10}', '$.a');
{}

sqlite> -- # 5.
sqlite> select json_remove('[0,1,2,3,4]', '$[10]');
[0,1,2,3,4]
sqlite> select json_remove('[0,1,2,3,4]', '$[#]');
[0,1,2,3,4]
sqlite> select json_remove('{"a":10, "b":20}', '$.z');
{"a":10,"b":20}
                    
  1. JSON Pathで位置を指定して要素を削除する
  2. 指定したJSON Path以下のパスの要素も削除される
  3. ルート要素を削除するとNULLが返る
  4. 配列やオブジェクト内の要素を全部削除すると、空の配列やオブジェクトが残る
  5. 存在しないJSON Pathを指定しても何も起こらずエラーも出力されない
引数に複数のJSON Pathを指定した場合

json_remove()の第2引数以降にJSON Pathを複数指定できる。 ただし、第2引数で指定された要素を削除された後のJSONデータに対し、 第3引数で指定されたJSON Pathが評価される、という順番のようなので 特に配列内の要素を順番を指定して削除する場合には注意すること。


sqlite> -- # 1.
sqlite> select json_remove('{"a":10, "b":20, "c":30, "d":40}', '$.a', '$.c');
{"b":20,"d":40}
sqlite> select json_remove('{"a":10, "b":20, "c":30, "d":40}', '$.a', '$.c', '$.d');
{"b":20}

sqlite> -- # 2.
sqlite> select json_remove('[0,1,2,3,4]', '$[0]', '$[2]');
[1,2,4]
sqlite> select json_remove('[0,1,2,3,4]', '$[0]', '$[1]');
[1,3,4]
sqlite> select json_remove('[0,1,2,3,4]', '$[0]', '$[0]', '$[0]');
[3,4]

sqlite> -- # 3.
sqlite> select json_remove('[0,1,2,3,4]', '$[0]', '$[0]');
[2,3,4]
sqlite> select json_remove(
   ...>             json_remove('[0,1,2,3,4]', '$[0]')
   ...>             , '$[0]'
   ...>         );
[2,3,4]
                    
  1. 複数のJSON Pathを指定して要素を削除出来る
  2. 配列の順番を指定する場合は順番に注意する必要がある
  3. この二つのSQLは同じ結果を返す
第1引数にJSONオブジェクト以外を指定した場合

テキスト型を指定した場合のみエラーになる模様。 他の型は「$」をJSON Pathに指定すれば削除される。


sqlite> .nullvalue [null]

sqlite> -- # 1.
sqlite> select json_remove(1, '$[0]');
1
sqlite> select json_remove('test', '$[0]');
Runtime error: malformed JSON
sqlite> select json_remove(true, '$[0]');
1
sqlite> select json_remove(false, '$[0]');
0

sqlite> -- # 2.
sqlite> select json_remove(1, '$');
[null]
sqlite> select json_remove('test', '$');
Runtime error: malformed JSON
sqlite> select json_remove(true, '$');
[null]
sqlite> select json_remove(false, '$');
[null]
                    
  1. テキストを指定した場合のみJSONエラーになる
  2. 「$」を指定すれば削除されてNULLが返る
引数を一つしか指定しなかった場合

第1引数がJSONとして認識されればエラーにならない


sqlite> .log strerr

sqlite> select json_remove(1);
1
sqlite> select json_remove('[0,1,2,3,4]');
[0,1,2,3,4]
sqlite> select json_remove(true);
1
sqlite> select json_remove(false);
0
sqlite> select json_remove('test');
Runtime error: malformed JSON
sqlite> select json_remove('$');
Runtime error: malformed JSON
                    

参考URL