【Oracle26ai新機能】BOOLEAN型の使い方|格納できる値と、0以外の数値がTRUEになる注意点【実行ログ付き】

  • URLをコピーしました!
Oracle AI Database
僕の作業環境
  • 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型の列に入るのかを確かめます。既存システムから移行するときに一番気になるのが、ここです。

STEP

文字列・数値・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のままで、表示は空欄になります。

既存のCHAR(1)やNUMBER(1)の値をINSERT … SELECTで移す場合も、’yes’や1/0のような値であれば、変換用の関数を挟まずに格納できます。

STEP

解釈できない値を格納する

次に、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として格納されました。

TRUE/FALSEとして解釈できない文字列は、エラーで拒否されます。

STEP

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になりました。数値として渡すか、文字列として渡すかで結果が変わる点に注意が必要です。

数値は「0ならFALSE、それ以外はTRUE」と覚えておくと分かりやすいです。数字を文字列で渡す場合は、’1’/’0’だけを使います。

BOOLEAN型のNULLの扱いと型変換(TO_BOOLEAN・CAST)

BOOLEAN型でつまずきやすいのが、NULLの扱いです。条件にNULLを含めるかどうかで、書き方が変わります。

STEP

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に変換されました。

NULLを「偽」として扱いたいときはIS TRUE、「真」として扱いたいときはIS NOT FALSEを使います。NULLを含む列を集計するときは、どちらに寄せるかを先に決めておくと、件数のずれを防げます。

STEP

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’になりました。

大文字の’TRUE’や’Y’も小文字と同じように変換できたため、アプリから’Y’や’yes’などが混在して届く場合でも、そのまま変換できます。VALUES句の使い方は「VALUES句(テーブル値コンストラクタ)の使い方」で解説しています。

SQLとPL/SQLでBOOLEAN型を使う

ここからは、BOOLEAN型を実際の表設計やSQLでどう使えるかを見ていきます。

STEP

論理式を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値論理のとおりです。

これまでCASE WHEN … THEN ‘Y’ ELSE ‘N’ ENDと書いていた部分を、論理式だけで書けます。なお、このSELECT文はFROM句を書かずに実行しています。FROM句の省略も23ai以降の機能で、「FROM DUALを省略したSELECTの使い方」で詳しく検証しています。

STEP

既定値・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の順に並びました。

フラグ列はNULLを許すと判定が3通りになり、扱いが複雑になります。実務では、既定値とNOT NULLをセットで付けるのがおすすめです。

なお、値が2種類しかない列は、一般的にB-tree索引の選択性が低く、表全体の多くの行を読む検索では索引が使われにくいです。

STEP

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に変わりました。

WHERE done = ‘Y’のような比較は不要で、列名だけで条件を書けます。フラグの切り替えもSET done = NOT doneの1文で済みます。

STEP

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を返すPL/SQL関数をSQLから呼べず、’Y’/’N’を返すラッパー関数を作ることがありました。SQLとPL/SQLの間でそのまま受け渡せるため、そうした変換用の関数は不要になります。

BOOLEAN型に変換した値の一覧

入力値結果
‘true’・’yes’・’y’・’on’・’t’・’1’(大文字の’TRUE’・’Y’も可)TRUE
‘false’・’no’・’n’・’off’・’0’FALSE
数値の0FALSE
0以外の数値(-1・0.5・2・100)TRUE
NULLNULL
‘maybe’、文字列の’2’ORA-61800

まとめ

BOOLEAN型は、真偽値を’Y’/’N’や1/0ではなく、TRUE/FALSEとして表とSQLで直接扱えるデータ型になります。

BOOLEAN型は、以下の手順で使い始められます。

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をセットで付けるのがおすすめです。

最後までご愛読ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次