順番に読み進めながら学べます

文字列・数値・論理型と暗黙の型変換

この記事は、基礎から複雑なSQL,SQLチューニングまでSQLの実践的なスキルを1からマスターする「SQL入門講座の一部」です。
typed_demoテーブルを題材に、宣言型と格納クラス、typeof()で見る '10' と123の相互変換、真偽を0 / 1で表すしくみ、そしてMySQLのCHAR/VARCHAR/INT/DECIMALの厳格型との違いを実際に動かして確かめます。

本記事で使うデータ — typed_demo テーブル

列を作るときINTEGER / TEXT / REALのようなを宣言し、その列に入る値の扱いを決めます。

本記事では、文字列・数値・論理(真偽)の 3 つの値が SQL でどう保存・比較されるか、そして本講座のコンソールが採用する型の扱い方が MySQL の厳格な型とどう違うかを順に確認します。

演習に入る前に、typed_demoテーブルの列定義データのサンプルを確認しておきます。(正しく実行できれば解説が表示されます)

PRAGMA table_info(typed_demo);で列名・宣言された型・主キーを確認してください。

SELECT * FROM typed_demo;で全行のデータをプレビューしてください。

SQL エディタ

クエリを実行してください

宣言された型と格納クラス — 値そのものが型を持つ

値が実際に持つ型を格納クラス(storage class)と呼び、NULL / INTEGER(整数)/ REAL(小数)/ TEXT(文字列)/ BLOB(バイナリ)の 5 種類があります。

ある値が現在どの格納クラスかはtypeof(値)関数で確認できます。

TEXTを宣言した列に数値らしい文字列を入れても、その列の方針が「文字列として扱う」なので文字列のまま保持されます。

一方、INTEGERを宣言した列に'123'のような数値らしい文字列を入れると、列の方針に従って整数123に変換されてから格納されます。

宣言された型と格納クラス
入れる値列の宣言型格納される型'123'INTEGER 列整数 123(typeof=integer)'10'TEXT 列文字列 '10'(typeof=text)
列に宣言した型は「どの種類として扱うか」の方針です。INTEGER 列に入れた '123' は整数に変換され、TEXT 列に入れた '10' は文字列のまま保持されます。実際の型は typeof() で値ごとに分かります。
-- 別テーブルで「列の宣言型が値の格納型を決める」ことを観察する例
-- INTEGER 列に数値らしい文字列を入れると整数化される
CREATE TABLE IF NOT EXISTS aff_probe(num INTEGER, txt TEXT);
INSERT OR IGNORE INTO aff_probe VALUES ('123','123'), ('hello','hello');

-- typeof で実際の格納クラスを確認
SELECT num, typeof(num) AS num_class,
       txt, typeof(txt) AS txt_class
FROM aff_probe;
-- num 列: '123' は integer に変換、'hello' は数値化できず text のまま
-- txt 列: どちらも text のまま

typed_demoの各列の値が、実際にはどの種類(整数 / 小数 / 文字列)として保存されているか」を確認したいという要件を想定します。

typed_demoからabcflagの各列の値を取り出してください。

② それぞれの列にtypeof()を適用した列も併せて取り出し、a_class / b_class / c_class / flag_classという別名を付けてください。

③ 2 行とも結果に出るよう、行を絞らずに取得してください。

SQL エディタ

クエリを実行してください

文字列と数値の相互変換 — '123' と 123 を行き来する

数値が必要な場面では文字列が自動的に数値へ、文字列が必要な場面では数値が文字列へ変換されます。

たとえば'123' + 0は文字列'123'が数値123に変換されて123を返し、算術演算では数値らしい文字列がそのまま計算に使えます。

逆に123 || ''||は文字列連結)では数値が文字列になります。

比較演算でも、片方がINTEGER列なら相手も数値として揃え、片方がTEXT列なら相手も文字列として揃えて比べます。

ただし列を介さずリテラルだけを比べる'1' = 1は数値方針が働かず、種類違いとして0(不一致)になります。

場面に応じて文字列と数値が変換される
変換結果'123' + 0'123' を数値 123 に123'abc' + 0数値化できず0 として扱う0
算術が必要な場面では数値らしい文字列が数値に、文字列連結が必要な場面では数値が文字列に変換されます。数値化できない 'abc' は算術では 0 として扱われます。
-- 文字列 <-> 数値 の変換を観察(読むだけの別例)
SELECT '123' + 0     AS str_to_num,   -- 文字列が数値 123 に
       'abc' + 0     AS not_a_num,    -- 数値化できず 0
       123 || ''     AS num_to_str,   -- 数値が文字列 '123' に
       typeof('123' + 0) AS class_after_add,
       '1' = 1       AS literal_cmp,  -- リテラルどうしは 0 (不一致)
       7 / 2         AS int_div,      -- 整数 / 整数 = 整数 3
       7.0 / 2       AS real_div;     -- 小数が混ざると 3.5

typed_demob列(TEXT)に入っている数値らしい文字列を、数値として計算・比較したい」という要件を想定します。

typed_demoからb列を取り出してください。

b0を足した値をb_plus0という別名で取り出してください。数値らしい行は数値になり、数値でない行は0になります。

③ さらに、bを数値として見たときに5より大きいかどうかを判定した結果をgt5という別名で取り出してください(b列と数値リテラルの比較なので数値どうしの比較になります)。

SQL エディタ

クエリを実行してください

論理(真偽)型 — TRUE / FALSE は 1 / 0 で表す

SQL には独立した論理型がなく、真偽は整数の1(真)と0(偽)で表します。

1 = 13 > 2のような比較式は、真なら1、偽なら0を返します。

CASE WHEN 列 THEN ...のように条件式が書ける場所では、0以外(典型的には1)が真、0が偽として扱われます。

NULLは真でも偽でもない第 3 の状態(不明)で、WHERECASEの条件としては偽と同じく「採用されない」扱いになります。

真偽は整数 1 / 0 で表す
式 / 値真偽の扱い1 / TRUE / 3>2真 (true)0 / FALSE / 1>2偽 (false)NULL不明 — 採用されない
比較式は真なら 1、偽なら 0 を返します。flag 列の 1 / 0 をそのまま条件に使え、NULL は真でも偽でもない第 3 の状態として扱われます。
-- 比較式は 1 / 0 を返す(読むだけの別例)
SELECT (1 = 1)  AS is_true,    -- 1
       (1 = 2)  AS is_false,   -- 0
       (3 > 2)  AS gt,         -- 1
       TRUE     AS true_kw,    -- 1 と同じ
       FALSE    AS false_kw;   -- 0 と同じ

-- フラグ列をそのまま条件に使う
SELECT a, flag,
  CASE WHEN flag THEN 'enabled' ELSE 'disabled' END AS state
FROM typed_demo;

typed_demoflag列(1 / 0 の整数)を、人が読めるラベルに変換して表示したい」という要件を想定します。

typed_demoからaflagを取り出してください。

flagをそのまま条件に使ったCASE WHEN ...で、真(1)の行は'enabled'、偽(0)の行は'disabled'となる列をstateという別名で 3 列目に追加してください。

③ 比較式が真偽でどんな値を返すかも確認するため、flag = 1の結果をis_onという別名で 4 列目に追加してください。

SQL エディタ

クエリを実行してください

MySQL の厳格な型との対比

ここまで見た暗黙の型変換は、数値らしい文字列を場面に応じて柔軟に変換する扱い方です。

一方MySQL や Oracle では型がより厳格で、CHAR(10) / VARCHAR(255) / TEXTの文字列型、INT / DECIMAL(10,2)の数値型を宣言すると、その列にはその型の値だけが入り、桁数や精度も宣言どおりに守られます。

文字列型に数値が暗黙変換されて入ることは原則なく、長さを超える値はエラーになるか切り詰められます。

下のコードは MySQL での型宣言の書き方です。

本講座のコンソールでは桁数チェックが出ない設計なので、VARCHAR(10)のような長さ制約を学ぶときは「MySQL ではこう書く」という形で覚えておくと、別の DB に移ったときにそのまま通用します。

暗黙の型変換 と MySQL の厳格型の対比
本講座のコンソール(暗黙の型変換)MySQL(厳格な型)INTEGER 列に '123' →整数 123 に変換して格納INT 列は数値のみ /VARCHAR(10) は 10 文字まで桁数・精度の強制はしない桁数超過はエラー / 切り詰め
本講座のコンソールは暗黙の型変換で、INTEGER 列に入れた '123' は整数に変換され実行は通ります。MySQL は厳格型で、宣言した型・桁数が守られ、合わない値はエラーや切り詰めになります。
-- MySQL での厳格な型宣言(読むだけ。このコンソールでは実行しない)
CREATE TABLE product (
  id        INT            PRIMARY KEY,   -- 整数のみ
  code      CHAR(8),                      -- 固定長 8 文字
  name      VARCHAR(100)   NOT NULL,      -- 最大 100 文字
  note      TEXT,                         -- 長い文字列
  price     DECIMAL(10,2)  NOT NULL,      -- 整数 8 桁 + 小数 2 桁
  in_stock  TINYINT(1)     DEFAULT 0      -- 0/1 で真偽を表すフラグ
);

-- MySQL では VARCHAR(100) に 101 文字を入れると
-- エラーになるか設定により切り詰められる。
-- INT 列に 'abc' を入れようとするとエラーになる。
-- 本講座のコンソールでは暗黙の型変換により実行自体は通る。

Tips — CHAR と VARCHAR の違いと使い分け

`CHAR(n)`固定長で、入れた値が n 文字未満なら末尾に空白を詰めて n 文字に揃えます。

`VARCHAR(n)`可変長で、入れた値の長さそのままを保持します(n は上限)。

`CHAR` を選ぶのは: 国コード('JP' / 'US')、性別コード、ハッシュ値の固定長部分など、長さが常に固定で揃っている値を入れる列。固定長なので比較やレコード位置計算がわずかに速い場面があります。

`VARCHAR` を選ぶのは: 名前・メールアドレス・タイトル・説明文など、長さがばらつく値を入れる列。実際に必要な分しか領域を取らないため、保存サイズが小さくなります。

迷ったら `VARCHAR` が無難です。CHAR を可変長データに使うと、末尾の空白詰めで意図しない比較ズレ('JP''JP ' の扱いの違い)を起こすことがあります。

typed_demob列(TEXT)に入っている値を数値として合計・平均し、flag列で何件が真かを数えたい」という要件を想定します。暗黙の型変換により、文字列型の列でも数値として集計できることを確認します。

typed_demob列の合計sum_b平均avg_bという別名で取り出してください。数値らしい行だけが数値として加算されます。

② 同じクエリでflag列の合計enabled_countという別名で取り出してください(flagは 1 / 0 なので、合計が真の件数になります)。

③ 行はグループ化せず、テーブル全体の 1 行の集計として取得してください。

SQL エディタ

クエリを実行してください
QUIZ

理解度チェック

まずは1問ずつ答えてみましょう。

Q1本講座のコンソールで、INTEGERを宣言した列に文字列'123'を INSERT したときの説明として正しいものはどれですか。

Q2SQL における真偽(論理値)の表し方として正しいものはどれですか。

Q3本講座のコンソールの暗黙の型変換と、MySQL の厳格な型の違いとして正しいものはどれですか。