主キー制約に違反するSQL文はどれか、更新される行数から考える
基本情報技術者試験 令和8年度 問7 / データベース › データ操作
過去問にチャレンジ
次のSQL文によって定義され,値が格納されている"商品"表に対して,制約違反で実行エラーとなるSQL文はどれか。 〔SQL文〕
CREATE TABLE 商品 (商品コード CHAR(4) PRIMARY KEY,商品名 VARCHAR(21), 仕入先コード CHAR(4),仕入単価 INT,在庫数 INT)
- ア
DELETE FROM 商品 WHERE 仕入先コード IS NULL - イ
INSERT INTO 商品 VALUES ('A555','空気清浄機','S005',60000,50) - ウ
UPDATE 商品 SET 商品コード = 'A666' WHERE 商品コード = 'A444' - エ
UPDATE 商品 SET 商品コード = 'A777' WHERE 在庫数 >= 20
会話形式の解説
講師この問題で大事なのは、商品コードにPRIMARY KEY、つまり主キーが指定されている点です。主キーの列には「同じ値を二度使えない」「空(NULL)のままにできない」という2つの決まりがあります。4つのSQL文を実行した後に、この決まりが崩れるものを探します。
受験者表の値と照らし合わせるのですね。私はまず、アがNULLを扱っているので怪しいと思いました。
講師アで条件にしているのは仕入先コードの列です。仕入先コードがNULLの行はA333だけなので、その1行が消えます。仕入先コードは主キーではないので、NULLが入っていても構いません。それに、行を消しても商品コードがかぶったり空になったりはしません。
受験者削除なら、残った行の商品コードは元のままですね。では、イのINSERTはどうですか。
講師追加する商品コードはA555です。今ある表はA111からA444までなので、どれとも一致しませんし、空でもありません。問題なく1行増えます。
受験者ウはA444をA666に変える文ですね。A666は表にまだないので、これも大丈夫そうです。
講師そのとおりです。WHERE句で商品コードがA444の行を指定しているので、書き換わるのは1行だけです。新しい値もほかの行とかぶりません。
受験者エのA777も表にない値です。ウと同じ理由でエラーにならないように見えて、迷っています。
講師そこがこの問題の引っかけです。エは商品コードではなく「在庫数が20以上」で行を選んでいます。条件に合う行がいくつあるか、表で数えてみてください。
受験者在庫数は、A111が0、A222が50、A333がNULL、A444が20です。>=は20ちょうども入るので、A222とA444の2行が選ばれます。
講師正しく数えられています。在庫数がNULLのA333は、比較しても結果が真にならないので選ばれません。選ばれた2行をどちらもA777にすると、商品コードがA777の行が2つになってしまいます。これは同じ値を二度使えないという決まりに反するので、エラーになります。
受験者変更後の値が表になくても、2行以上を同じ値にそろえたら重複が生まれるのですね。だから正解はエです。
講師はい。整理すると、INSERTでは追加する値が既存の値とかぶらないか、空でないかを確かめます。UPDATEで主キーを決まった値に書き換えるときは、それに加えて、WHERE句で何行が選ばれるかを必ず数えてください。また、主キー以外の列には今回は制約がないので、そこにNULLがあってもエラーの原因にはなりません。
まとめ
主キー(PRIMARY KEY)を指定した列には、値の重複を許さない性質と、NULLを許さない性質の両方があります。この問題では、在庫数が20以上の行の商品コードをA777に書き換えるUPDATE文がエラーになります。在庫数50のA222と在庫数20のA444の2行が選ばれ、どちらも同じ商品コードになるからです。A777は元の表にない値ですが、複数の行を同じ値に変えれば重複が生まれます。主キーをUPDATEする問題では、新しい値が表にあるかどうかに加えて、WHERE句で選ばれる行数も確認することが大切です。
解答・解説
正解はエです
この問題のテーマ
PRIMARY KEYを指定した列にどんな制約があるかを理解したうえで、表の中身に対して実行すると一意性違反のエラーになるSQL文を選ぶ問題です。正解はエです。
解き方の考え方
まず、主キーの商品コードには「重複しない」「NULLにならない」の2つの制約がかかることを確認します。次に、各SQL文について、WHERE句で何行が対象になるか、実行後の商品コードがどうなるかを表の値と照らし合わせます。そのうえで、実行後に商品コードの重複やNULLが生じる文を探します。エは在庫数20以上の2行(A222とA444)をどちらもA777に書き換えるため、主キーが重複します。したがって正解はエです。
選択肢ごとの解説
- ×ア
DELETE FROM 商品 WHERE 仕入先コード IS NULLアのDELETE文は、仕入先コードがNULLの行を削除します。該当するのはA333の1行だけです。行を削除しても主キーの重複やNULLは生じないので、主キー制約には違反しません。仕入先コードは主キーではないため、この列がNULLであること自体も問題になりません。 - ×イ
INSERT INTO 商品 VALUES ('A555','空気清浄機','S005',60000,50)イのINSERT文で追加する商品コードA555は、既存のA111〜A444のどれとも重複しません。NULLでもないため、主キー制約を満たしたまま挿入できます。 - ×ウ
UPDATE 商品 SET 商品コード = 'A666' WHERE 商品コード = 'A444'ウのUPDATE文は、商品コードがA444の1行だけを対象にします。変更後のA666は表の中でまだ使われていない値なので、重複は起きません。そのためエラーにならずに更新できます。 - ○エ
UPDATE 商品 SET 商品コード = 'A777' WHERE 在庫数 >= 20エのUPDATE文の条件「在庫数 >= 20」は20を含みます。そのため、在庫数50のA222と在庫数20のA444の2行が対象になり、在庫数0のA111とNULLのA333は外れます。2行ともに商品コードがA777になるので主キーが重複し、一意性制約違反でエラーになります。A777はもともと表にない値ですが、更新によって複数の行が同じ値になれば違反です。「表にない値だから大丈夫」と考えると引っかかるので注意してください。
補足
主キー以外の列には制約が付いていないため、アのように仕入先コードがNULLの行があっても、それを削除しても、エラーにはなりません。INSERT文では「既存の値と重複しないか」と「NULLでないか」を確認し、UPDATE文ではさらに「対象行の数」も確認する、と区別して覚えておくと応用できます。
POINT
- PRIMARY KEYを指定した列は、UNIQUE(重複不可)とNOT NULL(NULL不可)の性質を両方持ちます。
- UPDATE文で主キーを固定の値に変えるときは、WHERE句で対象になる行が何行あるかを必ず数えます。
- 対象が2行以上あれば、変更後の値が既存のデータになくても、更新後に重複して制約違反になります。
- 比較演算子の>=は境界の値を含むので、在庫数がちょうど20の行も対象になります。
- 在庫数がNULLの行は、比較条件の結果が真にならないため、WHERE句で選ばれません。
