INSERT
列名を書き、それぞれに値を与えます。書かなかった列には既定値が入ります。ここでは added_at が現在時刻になります。
1
INSERT INTO wishlists (customer_id, product_id)
VALUES (1, 288);
1 行を変更
ブラウザの別タブで Planche が開き、サンプルデータベースを読み込んだ状態でこのクエリが入ります。このページの例はどれも同じタブを使い回します。F9 を押すまで実行はされません。
1行変更。テーブルの列順に頼らず列名を明示して書くことが、誰かが列を1つ足した後もこの文が動き続ける理由になります。
データベースが拒否するもの
まったく同じ文をもう一度実行してみてください。
2
-- The same statement a second time. (customer_id, product_id) is the
-- primary key of wishlists, so the database refuses the duplicate.
INSERT INTO wishlists (customer_id, product_id)
VALUES (1, 288);
エラー
エラーになり、何も変わりません。wishlists には PRIMARY KEY (customer_id, product_id) があるので、同じ組み合わせは2つ存在できません。制約が拒否したのです。制約は回避すべき障害物ではありません。アプリのバグが、永久に残る誤ったデータに変わるのを止めているものです。
UPDATE と、いちばん大事な句
2つの習慣でこれはかなり起きにくくなります。ひとつは SET より先に WHERE を書くこと。もうひとつは、同じ FROM と同じ WHERE で SELECT として実行し、何が返るかを見てから変更することです。
2つめは Planche に任せられます。設定 › 安全性 › 影響行のプレビューを有効にすると、UPDATE や DELETE は対応する SELECT に書き換えられ、件数を数えて実行前に見せてくれます。読み取り専用の接続や、本番接続に色を付ける設定も同じ場所にあります。
4
SELECT id, first_name, last_name, loyalty_points
FROM customers
WHERE id = 1;
結果 — 1 行
| id | first_name | last_name | loyalty_points |
|---|---|---|---|
| 1 | Liam | Fischer | 3619 |
DELETE
サブクエリで対象行を選ぶ
UPDATE や DELETE の WHERE は普通の WHERE なので、サブクエリのレッスンの内容がそのまま使えます。別のテーブルの内容をもとに、あるテーブルの行を変えるときの書き方です。
6
-- Which rows to change is its own question, and a subquery can answer it.
UPDATE customers
SET loyalty_points = loyalty_points + 50
WHERE id IN (
SELECT customer_id
FROM orders
WHERE status = 'refunded'
AND total > 2000
);
242 行を変更
2,000を超える返金注文を持つ顧客が242人いて、その242行が変わりました。さっきの習慣がそのまま当てはまります。まず SELECT id FROM customers WHERE id IN (...) として実行し、件数を数えてください。間違いが潜むのはサブクエリだからです。
7
DELETE FROM wishlists
WHERE product_id IN (
SELECT id FROM products WHERE stock_quantity = 0
);
260 行を変更
NOT EXISTS と EXISTS もここで使えますし、否定形についてはサブクエリのレッスンで述べた理由から、そちらが安全です。一方で移植性がないのは、UPDATE や DELETE の中で直接結合する書き方です。エンジンごとに綴りが違い、そもそもできないエンジンもあります。専用の方言ページで5つすべてを扱います。
トランザクション
トランザクションは複数の文をひとまとめにし、全部起きるか何も起きないかにします。そしてコミットするまでは、結果を見て気を変えることもできます。
8
BEGIN;
UPDATE coupons
SET used_count = used_count + 1
WHERE code = 'WELCOME10';
SELECT code, used_count FROM coupons WHERE code = 'WELCOME10';
ROLLBACK;
結果 — 1 行
| code | used_count |
|---|---|
| WELCOME10 | 63 |
BEGIN で開始し、SELECT ではクーポンがすでに増えて見え、ROLLBACK で元に戻ります。ROLLBACK を COMMIT に変えれば、変更は確定します。件数が戻っていることを自分で確かめてください。
9
SELECT code, used_count FROM coupons WHERE code = 'WELCOME10';
結果 — 1 行
| code | used_count |
|---|---|
| WELCOME10 | 62 |
本番データベースで危ない変更をするときは、これが正しい道具です。トランザクションを開き、文を実行し、行数が想定どおりか確かめ、それから初めてコミットします。Planche にはモードとして用意してあります。接続 › 手動トランザクションにするとトランザクションを開いたままにし、ツールバーにコミットとロールバックが出るので、明示するまではどの文も仮のものになります。
ここまでで書けるもの
クエリが遅い理由を突き止めること以外は、ひととおりできます。それが最後のレッスンです。