
- OS:Oracle Linux 9.7
- 導入製品:Oracle AI Database 26ai Enterprise Edition Release 23.26.1.0.0
- 構成:CDB=orcl/PDB=ORCLPDB1
Oracleで「有効フラグ」や「削除済みフラグ」の列を作るとき、これまではCHAR(1)に’Y’/’N’を入れるか、NUMBER(1)に1/0を入れるのが定番でした。
ただ、この方法では’y’や’1’のような想定外の値が混ざりやすく、CHECK制約や変換用のCASE式をあちこちに書く必要がありました。Oracle Database 23ai以降は、SQLのデータ型としてBOOLEANが使えるため、この手間を減らせます。
本記事では、「BOOLEAN型の使い方」について、列に格納できる値、TO_BOOLEANとCASTによる変換、PL/SQLとの受け渡しを、実行ログとあわせて解説します。
- BOOLEAN型の列に格納できる値(文字列・数値・NULL)
- 数値と文字列で変換結果が変わるケース
- TO_BOOLEANとCASTによる変換
- 論理式をSELECT句で値として返す方法
- PL/SQLのBOOLEANとの受け渡し
BOOLEAN型とは
BOOLEAN型は、TRUE・FALSE・NULLの3つの値を持つデータ型です。これまでPL/SQLの中だけで使えたBOOLEANを、表の列やSQLの式でも使えるようになりました。
| 項目 | 内容 |
|---|---|
| 格納できる値 | TRUE/FALSE/NULL |
| 受け付けるリテラル | TRUE、FALSE、’yes’、’on’、’t’、1、0など |
| 数値への変換 | TRUE=1、FALSE=0 |
BOOLEAN型は、Oracle Database 23aiで追加されたSQLのデータ型です。一般的に、型名はBOOLEANのほかにBOOLとも書けます。
BOOLEAN型と組み合わせて使う関数・構文は、次の3つです。
- TO_BOOLEAN(式):文字列や数値をBOOLEANに変換する関数
- CAST(式 AS 型):値を指定した型に変換する構文。BOOLEANと文字列・数値の相互変換にも使える
- 論理式:比較(=、>など)やAND/OR/NOTで組み立てた式。結果はTRUE/FALSE/NULLのいずれかになる
これまで論理式はWHERE句やCASE式の条件にしか書けず、結果を値として取り出すにはCASE式で’Y’/’N’などに変換する必要がありました。BOOLEAN型が使えるようになったことで、論理式の結果をそのまま値として扱えます。
なお、BOOLEANはSQL標準で定められたデータ型で、PostgreSQLなど他のデータベースでは以前から使えました。一般的に、他のデータベースからOracleへ移行するときに、真偽値の列を’Y’/’N’へ置き換える作業が必要だった部分です。また、公式ドキュメントでは、グループ内の値がすべてTRUEかを調べるBOOLEAN_AND_AGGと、1つでもTRUEがあるかを調べるBOOLEAN_OR_AGGの集計関数も説明されています(本記事では試していません)。
BOOLEAN型の列に格納できる値
まずは、どんな値がBOOLEAN型の列に入るのかを確かめます。既存システムから移行するときに一番気になるのが、ここです。
文字列・数値・NULLを格納する
BOOLEAN型の列を持つ表を作り、TRUE/FALSE/NULLに加えて、文字列(’yes’・’off’・’t’)と数値(0・1)の8行を登録しました。
SQL> CREATE TABLE V26_APP.B (id NUMBER, flag BOOLEAN);
Table created.
SQL> INSERT INTO V26_APP.B VALUES (1, TRUE), (2, FALSE), (3, NULL), (4, 'yes'), (5, 0), (6, 'off'), (7, 1), (8, 't');
8 rows created.
SQL> SELECT id, flag FROM V26_APP.B ORDER BY id;
ID FLAG
---------- -----------
1 TRUE
2 FALSE
3
4 TRUE
5 FALSE
6 FALSE
7 TRUE
8 TRUE
8 rows selected.結果は、文字列と数値もすべてTRUEかFALSEに変換されて格納されました。NULLはNULLのままで、表示は空欄になります。
解釈できない値を格納する
次に、TRUE/FALSEのどちらとも取れない’maybe’と、数値の2を登録しました。
SQL> INSERT INTO V26_APP.B VALUES (9, 'maybe');
INSERT INTO V26_APP.B VALUES (9, 'maybe')
*
ERROR at line 1:
ORA-61800: invalid boolean literal: maybe
SQL> INSERT INTO V26_APP.B VALUES (10, 2);
1 row created.
SQL> SELECT id, flag FROM V26_APP.B ORDER BY id;
ID FLAG
---------- -----------
1 TRUE
2 FALSE
3
4 TRUE
5 FALSE
6 FALSE
7 TRUE
8 TRUE
10 TRUE
9 rows selected.結果は、’maybe’がORA-61800(invalid boolean literal)になり、数値の2はTRUEとして格納されました。
0以外の数値と、数字の文字列を比べる
数値の扱いをもう少し細かく見るため、負の数(-1)・0・小数(0.5)・1・2・100・NULLを登録し、CASTとTO_BOOLEANでも同じ値を変換しました。
SQL> CREATE TABLE V26_BLOG.n (v NUMBER, b BOOLEAN);
Table created.
SQL> INSERT INTO V26_BLOG.n VALUES (-1, -1), (0, 0), (0.5, 0.5), (1, 1), (2, 2), (100, 100), (NULL, NULL);
7 rows created.
SQL> SELECT v, b FROM V26_BLOG.n ORDER BY v NULLS LAST;
V B
---------- -----------
-1 TRUE
0 FALSE
.5 TRUE
1 TRUE
2 TRUE
100 TRUE
7 rows selected.
SQL> SELECT CAST(-1 AS BOOLEAN) AS m1, CAST(0.5 AS BOOLEAN) AS half, CAST(2 AS BOOLEAN) AS two, CAST(100 AS BOOLEAN) AS hundred;
M1 HALF TWO HUNDRED
----------- ----------- ----------- -----------
TRUE TRUE TRUE TRUE
1 row selected.
SQL> SELECT TO_BOOLEAN(2) AS b;
B
-----------
TRUE
1 row selected.
SQL> SELECT TO_BOOLEAN('2') AS b;
SELECT TO_BOOLEAN('2') AS b
*
ERROR at line 1:
ORA-61800: invalid boolean literal: 2結果は、0だけがFALSEになり、-1・0.5・2・100はすべてTRUEになりました。NULLはNULLのまま格納され、ログでは100の行の下に空行として表示されています。
一方で、TO_BOOLEANは数値の2をTRUEにしましたが、文字列の’2’はORA-61800になりました。数値として渡すか、文字列として渡すかで結果が変わる点に注意が必要です。
BOOLEAN型のNULLの扱いと型変換(TO_BOOLEAN・CAST)
BOOLEAN型でつまずきやすいのが、NULLの扱いです。条件にNULLを含めるかどうかで、書き方が変わります。
IS TRUE/IS NOT FALSEでNULLを判定する
IS TRUE、IS NOT FALSE、TO_CHAR、TO_NUMBERの結果を、1つのSELECT文で比べました。
SQL> SELECT id, flag IS TRUE AS is_t, flag IS NOT FALSE AS not_f, TO_CHAR(flag) AS chr, TO_NUMBER(flag) AS num FROM V26_APP.B ORDER BY id;
ID IS_T NOT_F CHR NUM
---------- ----------- ----------- ----- ----------
1 TRUE TRUE TRUE 1
2 FALSE FALSE FALSE 0
3 FALSE TRUE
4 TRUE TRUE TRUE 1
5 FALSE FALSE FALSE 0
6 FALSE FALSE FALSE 0
7 TRUE TRUE TRUE 1
8 TRUE TRUE TRUE 1
8 rows selected.結果は、NULLの行(ID=3)でIS TRUEがFALSE、IS NOT FALSEがTRUEになりました。TO_CHARとTO_NUMBERはNULLを返し、TRUEは1、FALSEは0に変換されました。
TO_BOOLEANとCASTで変換する
TO_BOOLEAN関数に11種類の文字列を渡し、大文字の’Y’も試しました。11種類の文字列は、FROM句にVALUES句(テーブル値コンストラクタ)を書いて、1列の表として一度に渡しています。あわせて、CASTで文字列・数値からBOOLEANへ、BOOLEANから数値・文字列への変換も確かめました。
SQL> SELECT s, TO_BOOLEAN(s) AS b FROM (VALUES ('true'), ('TRUE'), ('yes'), ('y'), ('on'), ('1'), ('false'), ('no'), ('n'), ('off'), ('0')) v(s);
S B
-------- -----------
true TRUE
TRUE TRUE
yes TRUE
y TRUE
on TRUE
1 TRUE
false FALSE
no FALSE
n FALSE
off FALSE
0 FALSE
11 rows selected.
SQL> SELECT TO_BOOLEAN('Y') AS b;
B
-----------
TRUE
1 row selected.
SQL> SELECT CAST('true' AS BOOLEAN) AS c, CAST(0 AS BOOLEAN) AS z, CAST(TRUE AS NUMBER) AS n, CAST(FALSE AS VARCHAR2(10)) AS v;
C Z N V
----------- ----------- ---------- ----------
TRUE FALSE 1 FALSE
1 row selected.結果は、’true’・’yes’・’y’・’on’・’1’がTRUE、’false’・’no’・’n’・’off’・’0’がFALSEになりました。大文字の’TRUE’や’Y’も変換できました。CASTでは、TRUEが数値の1に、FALSEが文字列の’FALSE’になりました。
SQLとPL/SQLでBOOLEAN型を使う
ここからは、BOOLEAN型を実際の表設計やSQLでどう使えるかを見ていきます。
論理式をSELECT句で返す
比較(>、=)と、AND/OR/NOTを使った論理式を、SELECT句にそのまま書きました。
SQL> SELECT 1 > 0 AS gt, 1 = 2 AS eq, (1 > 0) AND (2 > 3) AS a, (1 > 0) OR NULL AS o, NOT (1 > 0) AS n;
GT EQ A O N
----------- ----------- ----------- ----------- -----------
TRUE FALSE FALSE TRUE FALSE
1 row selected.結果は、それぞれの論理式の値がTRUE/FALSEの列として返りました。(1 > 0) OR NULLはTRUEになり、従来の3値論理のとおりです。
既定値・NOT NULL・索引を設定する
タスク管理の表を想定し、DEFAULT FALSE NOT NULLのBOOLEAN列を持つ表を作りました。あわせて索引を作成し、ORDER BYで並べ替えました。
SQL> CREATE TABLE V26_BLOG.task (id NUMBER PRIMARY KEY, title VARCHAR2(20), done BOOLEAN DEFAULT FALSE NOT NULL);
Table created.
SQL> INSERT INTO V26_BLOG.task (id, title) VALUES (1, 'a');
1 row created.
SQL> INSERT INTO V26_BLOG.task VALUES (2, 'b', TRUE), (3, 'c', 'yes');
2 rows created.
SQL> INSERT INTO V26_BLOG.task VALUES (4, 'd', NULL);
INSERT INTO V26_BLOG.task VALUES (4, 'd', NULL)
*
ERROR at line 1:
ORA-01400: cannot insert NULL into ("V26_BLOG"."TASK"."DONE")
SQL> CREATE INDEX V26_BLOG.task_done_ix ON V26_BLOG.task (done);
Index created.
SQL> SELECT id, title, done FROM V26_BLOG.task ORDER BY done, id;
ID TITLE DONE
---------- -------------------- -----------
1 a FALSE
2 b TRUE
3 c TRUE
3 rows selected.結果は、値を省略した行はFALSEになり、NULLはORA-01400で拒否されました。ORDER BYでは、FALSE→TRUEの順に並びました。
なお、値が2種類しかない列は、一般的にB-tree索引の選択性が低く、表全体の多くの行を読む検索では索引が使われにくいです。
FILTER句とNOTで集計・更新する
集計のFILTER句にBOOLEAN列をそのまま条件として書き、UPDATEではNOTで値を反転させました。
SQL> SELECT COUNT(*) FILTER (WHERE done) AS done_cnt, COUNT(*) FILTER (WHERE NOT done) AS open_cnt FROM V26_BLOG.task;
DONE_CNT OPEN_CNT
---------- ----------
2 1
1 row selected.
SQL> UPDATE V26_BLOG.task SET done = NOT done WHERE id = 1;
1 row updated.
SQL> SELECT id, done FROM V26_BLOG.task WHERE id = 1;
ID DONE
---------- -----------
1 TRUE
1 row selected.結果は、完了が2件・未完了が1件と数えられ、ID=1はFALSEからTRUEに変わりました。
PL/SQLとBOOLEANを受け渡す
BOOLEANを返すPL/SQL関数をSELECT句から呼び、さらに列の値をPL/SQLのBOOLEAN変数に取得しました。
SQL> CREATE FUNCTION V26_BLOG.is_even(n NUMBER) RETURN BOOLEAN IS BEGIN RETURN MOD(n, 2) = 0; END;
Function created.
SQL> SELECT id, V26_BLOG.is_even(id) AS even FROM V26_BLOG.task ORDER BY id;
ID EVEN
---------- -----------
1 FALSE
2 TRUE
3 FALSE
3 rows selected.
SQL> DECLARE b BOOLEAN; BEGIN SELECT done INTO b FROM V26_BLOG.task WHERE id = 2; DBMS_OUTPUT.PUT_LINE('PL/SQL got: ' || CASE WHEN b THEN 'TRUE' ELSE 'FALSE' END); END;
PL/SQL got: TRUE
PL/SQL procedure successfully completed.結果は、関数の戻り値が列として表示され、変数にはTRUEが入りました。
BOOLEAN型に変換した値の一覧
| 入力値 | 結果 |
|---|---|
| ‘true’・’yes’・’y’・’on’・’t’・’1’(大文字の’TRUE’・’Y’も可) | TRUE |
| ‘false’・’no’・’n’・’off’・’0’ | FALSE |
| 数値の0 | FALSE |
| 0以外の数値(-1・0.5・2・100) | TRUE |
| NULL | NULL |
| ‘maybe’、文字列の’2’ | ORA-61800 |
まとめ
BOOLEAN型は、真偽値を’Y’/’N’や1/0ではなく、TRUE/FALSEとして表とSQLで直接扱えるデータ型になります。
BOOLEAN型は、以下の手順で使い始められます。
- BOOLEAN型の列を持つ表を作る(DEFAULT FALSE NOT NULLを付けるのがおすすめ)
- TRUE/FALSEのほか、’yes’・’off’・’t’・1・0などで値を登録する
- 解釈できない値(’maybe’、文字列の’2’)はORA-61800になることを前提に、移行元の値を確認する
- IS TRUE/IS NOT FALSEで、NULLの寄せ方を決めて判定する
- TO_BOOLEANとCASTで、文字列・数値との相互変換を行う
- 論理式をSELECT句で返し、FILTER句やSET done = NOT doneで集計・更新する
- BOOLEANを返すPL/SQL関数をSQLから呼び、PL/SQL変数に値を受け取る
文字列の’yes’や数値の1/0もそのまま格納できる一方で、数値は0以外がすべてTRUEになり、文字列の’2’はエラーになるなど、渡し方によって結果が変わる点には注意が必要です。既存のCHAR(1)の列をいきなり置き換えるよりも、新しく作る表から使い始め、既定値とNOT NULLをセットで付けるのがおすすめです。
最後までご愛読ありがとうございました。
