CREATE TABLE books (
id INTEGER PRIMARY KEY,
title TEXT,
author TEXT,
year INTEGER,
pages INTEGER
);
INSERT INTO books (title, author, year, pages) VALUES
('Dune', 'Herbert', 1965, 688),
('Neuromancer', 'Gibson', 1984, 271),
('Untitled Draft', 'Anonymous', NULL, 120);
-- year が NULL の行があるにもかかわらず、何も返らない:
SELECT title FROM books WHERE year = NULL;
-- 正しい書き方はこちら:
SELECT title FROM books WHERE year IS NULL;
SELECT title FROM books WHERE year IS NOT NULL;
IS NULL と IS NOT NULL だけが NULL を直接判定できる演算子です。これは指に覚え込ませてください。それ以外の比較は NULL との比較がすべて NULL を返し、該当する行が静かに結果から消えてしまいます。
否定でも同じ罠があります。WHERE author != 'Asimov' は author IS NULL の行を返してくれません。なぜなら NULL != 'Asimov' の結果も NULL になるからです。NULL の行も含めたいときは、WHERE author != 'Asimov' OR author IS NULL のように明示的に書く必要があります。
IN と BETWEEN:毎日のように使うショートカット
IN 演算子はリストに値が含まれているかを判定します。OR をいくつもつなげる代わりにスッキリ書ける書き方です。
CREATE TABLE books (
id INTEGER PRIMARY KEY,
title TEXT,
author TEXT,
year INTEGER,
pages INTEGER
);
INSERT INTO books (title, author, year, pages) VALUES
('Dune', 'Herbert', 1965, 688),
('Neuromancer', 'Gibson', 1984, 271),
('Foundation', 'Asimov', 1951, 244),
('Hyperion', 'Simmons', 1989, 482),
('The Martian', 'Weir', 2011, 369);
SELECT title, author FROM books
WHERE author IN ('Herbert', 'Asimov', 'Weir');
SELECT title FROM books
WHERE year NOT IN (1965, 1984);
BETWEEN は範囲を指定して絞り込む条件で、両端を含むのがポイントです。
CREATE TABLE books (
id INTEGER PRIMARY KEY,
title TEXT,
author TEXT,
year INTEGER,
pages INTEGER
);
INSERT INTO books (title, author, year, pages) VALUES
('Dune', 'Herbert', 1965, 688),
('Neuromancer', 'Gibson', 1984, 271),
('Foundation', 'Asimov', 1951, 244),
('Hyperion', 'Simmons', 1989, 482),
('The Martian', 'Weir', 2011, 369);
SELECT title, year FROM books
WHERE year BETWEEN 1980 AND 2000;
SELECT title, pages FROM books
WHERE pages NOT BETWEEN 300 AND 500;
year BETWEEN 1980 AND 2000 は year >= 1980 AND year <= 2000 とまったく同じ意味で、単に書き方が短いだけです。注意点としては、両端の値も含まれることを覚えておきましょう。両端を除外したい場合は、比較演算子で書き下す必要があります。
IN と NULL の組み合わせについても一言。WHERE column NOT IN (1, 2, NULL) と書くと、いかなる行も返ってきません。なぜなら NULL との比較結果は常に NULL になるからです。リストから NULL を除外するか、IS NULL を使って別途扱うようにしましょう。
LIKE によるパターンマッチング
LIKE は文字列のパターンマッチングを行う演算子で、2種類のワイルドカードが使えます。
% は任意の長さの文字列にマッチします(0文字でもOK)。
_ はちょうど1文字にマッチします。
CREATE TABLE books (
id INTEGER PRIMARY KEY,
title TEXT,
author TEXT,
year INTEGER,
pages INTEGER
);
INSERT INTO books (title, author, year, pages) VALUES
('Dune', 'Herbert', 1965, 688),
('Neuromancer', 'Gibson', 1984, 271),
('Foundation', 'Asimov', 1951, 244),
('Hyperion', 'Simmons', 1989, 482),
('The Martian', 'Weir', 2011, 369);
-- "The" で始まるタイトル:
SELECT title FROM books WHERE title LIKE 'The %';
-- "ion" を含むタイトル:
SELECT title FROM books WHERE title LIKE '%ion%';
-- 4文字の著者名:
SELECT author FROM books WHERE author LIKE '____';
SQLiteのLIKEは、ASCII文字に関してはデフォルトで大文字小文字を区別しません。つまり 'Dune' LIKE 'dune' は真になります。Postgresから来た人にとってはちょっと意外かもしれませんね。PostgresではLIKEは大文字小文字を区別し、区別しないバージョンはILIKEとして用意されています(ちなみにSQLiteにILIKEはありません)。
CREATE TABLE books (
id INTEGER PRIMARY KEY,
title TEXT,
author TEXT,
year INTEGER,
pages INTEGER
);
INSERT INTO books (title, author, year, pages) VALUES
('Dune', 'Herbert', 1965, 688),
('Neuromancer', 'Gibson', 1984, 271),
('Foundation', 'Asimov', 1951, 244),
('Hyperion', 'Simmons', 1989, 482),
('The Martian', 'Weir', 2011, 369);
SELECT title FROM books WHERE title GLOB 'The *';
SELECT title FROM books WHERE title GLOB 'D*';
GLOB 'd*' だと、大文字小文字が区別されるので何もマッチしません。
日付で絞り込む
SQLite は日付をテキスト(通常は YYYY-MM-DD か ISO 8601 形式)として保存します。そのため、ISO 形式さえ守っていれば、文字列の比較がそのまま日付の比較として機能してくれます。
CREATE TABLE events (
id INTEGER PRIMARY KEY,
name TEXT,
occurred_on TEXT
);
INSERT INTO events (name, occurred_on) VALUES
('ローンチ', '2024-01-15'),
('パッチ', '2024-03-22'),
('リリース', '2024-11-08'),
('ホットフィックス', '2025-02-01');
SELECT name FROM events
WHERE occurred_on >= '2024-06-01';
SELECT name FROM events
WHERE occurred_on BETWEEN '2024-01-01' AND '2024-12-31';
CREATE TABLE books (
id INTEGER PRIMARY KEY,
title TEXT,
author TEXT,
year INTEGER,
pages INTEGER
);
INSERT INTO books (title, author, year, pages) VALUES
('Dune', 'Herbert', 1965, 688),
('Neuromancer', 'Gibson', 1984, 271),
('Foundation', 'Asimov', 1951, 244),
('Hyperion', 'Simmons', 1989, 482),
('The Martian', 'Weir', 2011, 369),
('Untitled Draft', 'Anonymous', NULL, 120);
SELECT title, author, year, pages
FROM books
WHERE year IS NOT NULL
AND year BETWEEN 1950 AND 2000
AND (author IN ('Herbert', 'Gibson') OR pages > 400)
AND title NOT LIKE '%Draft%';
上から順に読んでみてください。年が判明していて、範囲内に収まり、指定した2人の著者のどちらか または 十分な長さがあり、かつ下書きではない行だけが残ります。これこそ WHERE 句の本領発揮で、小さくて読みやすい条件を組み合わせて、狙ったレコードをきっちり絞り込めるわけです。
身につけておきたい習慣が2つあります。
条件は1行ずつインデントして書く。長い WHERE 句を1行にまとめると、あっという間に読めなくなります。