C言語+MySQL入門|商品を登録・表示する

C言語+MySQL入門|商品を登録・表示する

これまでの記事で、商品テーブルのproductsと在庫履歴テーブルのstock_historyを作成し、外部キーで関連付けました。

今回は、productsに実際の商品を登録し、保存されたデータを表示します。データを追加するINSERTと、データを取得するSELECTを使って、テーブルを操作してみましょう。

この記事では、次の内容を学びます。

  • INSERTで商品を1件登録する。
  • 自動採番された商品IDと、列の初期値を確認する。
  • 複数の商品をまとめて登録する。
  • SELECTで表示する列や行を選ぶ。
  • ORDER BYで表示順を指定する。

ここで使うSQLは、後でCプログラムから商品を登録・表示するときにも基本となります。まずはMySQLクライアントから実行し、SQLと結果の対応を確認していきましょう。

今回登録する商品を確認しよう

今回は、次の3つの商品を登録します。

商品名単価登録時の在庫数
ノート180.000
ボールペン120.000
クリアファイル90.000

この記事では、商品の基本情報を登録するところから始めるため、在庫数はすべて0とします。実際の入庫や出庫を記録する処理は、後で扱います。

productsには5つの列がありますが、今回のINSERTで指定するのは、商品名と単価の2つです。

列名今回の登録方法
product_id省略し、AUTO_INCREMENTで自動採番する
product_name商品名を指定する
price単価を指定する
stock省略し、DEFAULTで設定した0を使う
created_at省略し、登録時の日時を使う

テーブル作成時に設定した自動採番や初期値が、ここで役立ちます。

図1:指定した値と初期値を組み合わせて商品を登録する

この図から分かること

INSERTでは、すべての列の値を毎回指定する必要はありません。

今回のproductsでは、商品名と単価を指定すると、商品ID、在庫数、登録日時はテーブルの設定に従って決まります。省略できる列は、その列に設定した自動採番や初期値によって異なります。

データベースと登録前の状態を確認しよう

MySQLクライアントへ管理作業用のアカウントで接続し、mysql>が表示されている状態で進めます。

まず、inventory_dbを選択します。

USE inventory_db;
実行結果の例
Database changed

続けて、登録済みの商品数を確認しましょう。

SELECT COUNT(*) AS product_count
FROM products;
実行結果の例
+---------------+
| product_count |
+---------------+
|             0 |
+---------------+
1 row in set (0.00 sec)

前の記事までの手順どおりであれば、商品はまだ登録されていません。

以下の実行結果は、新しく作成したproductsに、登録用のSQLを上から順に各1回実行した場合の例です。すでに登録や削除を試している場合は、商品IDや件数が異なることがあります。

INSERTは、実行するたびに新しい行を追加します。 商品名には一意制約を設定していないため、同じSQLを繰り返すと、同じ名前の商品が別の商品IDで追加されます。

なお、この記事では、MySQLの既定の動作である自動コミットが有効な接続を前提にします。この状態では、成功したINSERTはその都度確定します。

INSERTで商品を1件登録しよう

最初に、ノートを1件登録します。

INSERT INTOの後ろには登録先のテーブル名を書き、その後ろの丸括弧に、値を指定する列名を並べます。VALUESの後ろには、その列に入れる値を書きます。

商品名と単価を指定してノートを登録するSQL

ファイル名: insert_first_product.sql

USE inventory_db;

INSERT INTO products (product_name, price)
VALUES ('ノート', 180.00);
実行結果の例
Query OK, 1 row affected (0.01 sec)

1 row affectedは、このINSERTによって1行が追加されたことを示します。処理時間は環境によって異なります。

今回のSQLは、次のように読み取れます。

SQLの部分意味
INSERT INTO productsproductsへ新しい行を追加する
product_name, price値を指定する列を、この順番で並べる
VALUES登録する値を指定する
ノートproduct_nameに保存する文字列
180.00priceに保存する数値

列名と値は、左から順に対応します。

今回の列の並びはproduct_name、priceなので、値も商品名、単価の順番にしています。指定する列の数と、値の数も一致させましょう。

SQLの文字列と数値の書き方

SQLの文字列データは、半角のシングルクォートで囲みます。今回のノートは文字列なので、SQL内では引用符が必要です。

一方、180.00は数値として指定しているため、引用符で囲みません。

データの種類SQLでの扱い
商品名などの文字列文字列リテラルとして、シングルクォートで囲む
単価などの数値数値をそのまま書く
INSERTやVALUESなどのキーワード引用符で囲まない
productsやpriceなどの識別子今回の名前では、そのまま書く

ここでの引用符は、文字列データを表すSQLの構文です。命令やファイル名を飾るためのものではありません。

自動採番された商品IDを確認しよう

登録に成功したら、同じ接続で、別のINSERTを実行する前に次のSQLを実行します。

SELECT LAST_INSERT_ID() AS new_product_id;
実行結果の例
+----------------+
| new_product_id |
+----------------+
|              1 |
+----------------+
1 row in set (0.00 sec)

LAST_INSERT_ID()を使うと、直前のINSERTで自動採番されたIDを確認できます。

今回のように1行を登録した場合は、その商品のproduct_idが返されます。この値は接続ごとに管理されるため、別の接続で行われた登録の影響は受けません。

新しく作成したテーブルでは、通常は1から始まります。ただし、登録や削除などを試した後は、1になるとは限りません。

商品IDを確認するために、最大の商品IDを調べたり、プログラムで次の番号を予測したりする必要はありません。登録結果として得られたIDを使うことが大切です。

SELECTで登録した商品を表示しよう

次に、productsの内容を表示します。

SELECT *
FROM products
ORDER BY product_id;
実行結果の例
+------------+--------------+--------+-------+---------------------+
| product_id | product_name | price  | stock | created_at          |
+------------+--------------+--------+-------+---------------------+
|          1 | ノート       | 180.00 |     0 | 2026-10-04 02:49:23 |
+------------+--------------+--------+-------+---------------------+
1 row in set (0.00 sec)
product_idproduct_namepricestockcreated_at
1ノート180.0002026-10-04 10:00:00

created_atには、実際に登録した日時が表示されます。表の日時は例です。

各部分の意味を確認しましょう。

SQLの部分意味
SELECT *すべての列を取得する
FROM productsproductsからデータを取得する
ORDER BY product_id商品IDの昇順で並べる

今回の結果では、INSERTで指定した商品名と単価に加えて、次の値も確認できます。

  • product_idに、自動採番されたIDが入っている。
  • stockに、既定値の0が入っている。
  • created_atに、登録時の日時が入っている。

SELECTは、保存されているデータを取得する操作です。今回のようなSELECTを何度実行しても、商品が増えたり、値が変更されたりすることはありません。

複数の商品をまとめて登録しよう

続けて、ボールペンとクリアファイルを登録します。

VALUESの後ろに、丸括弧で囲んだ値の組をカンマで区切って並べると、1つのINSERTで複数行を追加できます。

ボールペンとクリアファイルをまとめて登録するSQL

ファイル名: insert_additional_products.sql

USE inventory_db;

INSERT INTO products (product_name, price)
VALUES
    ('ボールペン', 120.00),
    ('クリアファイル', 90.00);
実行結果の例
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

2 rows affectedは、2行が追加されたことを示します。

今回も、商品ID、在庫数、登録日時は省略しています。そのため、商品IDは自動採番され、在庫数は0、登録日時はこのINSERTを実行した時点の日時になります。

括弧1組が1商品分に対応し、それぞれの括弧の中には、商品名と単価の2つの値を指定しています。

なお、複数行のINSERTの後でLAST_INSERT_ID()を実行すると、そのINSERTで最初に自動採番されたIDが返されます。登録したすべてのIDが一覧で返されるわけではありません。

必要な列を指定して一覧表示しよう

今度は、表示する列を明示して、3つの商品を確認します。

SELECT product_id, product_name, price, stock
FROM products
ORDER BY product_id;
実行結果の例
+------------+----------------+--------+-------+
| product_id | product_name   | price  | stock |
+------------+----------------+--------+-------+
|          1 | ノート         | 180.00 |     0 |
|          2 | ボールペン     | 120.00 |     0 |
|          3 | クリアファイル |  90.00 |     0 |
+------------+----------------+--------+-------+
3 rows in set (0.00 sec)
product_idproduct_namepricestock
1ノート180.000
2ボールペン120.000
3クリアファイル90.000

SELECTの後ろに列名を並べると、指定した列だけを取得できます。

今回はcreated_atを指定していないため、登録日時は結果に表示されません。ただし、テーブルから登録日時が削除されたわけではありません。

また、列はSELECTに書いた順番で表示されます。

SELECT *はテーブルの内容を手早く確認するときに便利です。一方、Cプログラムで結果を読み取るときには、必要な列を明示しておくと、取得する内容や順番を把握しやすくなります。

図2:INSERTで追加し、SELECTで保存結果を確認する

この図から分かること

INSERTは、テーブルに新しい行を追加する操作です。SELECTは、保存されているデータを取得する操作です。

登録後にSELECTを実行すると、保存した値や自動設定された値を確認できます。登録と確認を組み合わせながら進めると、SQLの結果を理解しやすくなります。

WHEREで表示する商品を絞り込もう

商品数が増えてくると、すべての商品ではなく、必要な商品だけを確認したくなります。

そのようなときは、WHEREで条件を指定します。WHEREを付けると、条件を満たす行だけが取得されます。

商品IDを指定して1件表示する

商品IDが1の商品を表示してみましょう。

SELECT product_id, product_name, price, stock
FROM products
WHERE product_id = 1;
実行結果の例
+------------+--------------+--------+-------+
| product_id | product_name | price  | stock |
+------------+--------------+--------+-------+
|          1 | ノート       | 180.00 |     0 |
+------------+--------------+--------+-------+
1 row in set (0.00 sec)

product_idは主キーなので、条件に一致する商品は最大1件です。

実際に採番されたIDが異なる場合は、一覧で確認したIDに置き換えてください。

なお、SQLで等しいかどうかを比較するときは、=を使います。C言語の等値比較で使う==との違いを押さえておきましょう。

単価の条件で商品を絞り込む

次は、単価が120以上の商品を表示します。

SELECT product_id, product_name, price
FROM products
WHERE price >= 120.00
ORDER BY product_id;
実行結果の例
+------------+--------------+--------+
| product_id | product_name | price  |
+------------+--------------+--------+
|          1 | ノート       | 180.00 |
|          2 | ボールペン   | 120.00 |
+------------+--------------+--------+
2 rows in set (0.00 sec)

price >= 120.00は、単価が120.00以上という条件です。クリアファイルの単価は90.00なので、結果には含まれません。

ここでは、行と列を別々に選んでいます。

  • SELECTの列名で、表示する項目を選ぶ。
  • WHEREの条件で、表示する商品を選ぶ。

WHEREで表示対象から外れた商品も、テーブルにはそのまま保存されています。

条件に一致する商品がない場合

単価が1000を超える商品を検索してみます。

SELECT product_id, product_name, price
FROM products
WHERE price > 1000.00
ORDER BY product_id;
実行結果の例
Empty set (0.00 sec)

Empty setは、条件に一致する行がなかったことを示します。

SQLの実行に失敗したわけではありません。Cプログラムでも、検索結果が0件の場合と、SQLの実行エラーは区別して扱います。

ORDER BYで表示順を指定しよう

商品の一覧を、単価が安い順に表示してみましょう。

SELECT product_id, product_name, price
FROM products
ORDER BY price ASC, product_id ASC;
実行結果の例
+------------+----------------+--------+
| product_id | product_name   | price  |
+------------+----------------+--------+
|          3 | クリアファイル |  90.00 |
|          2 | ボールペン     | 120.00 |
|          1 | ノート         | 180.00 |
+------------+----------------+--------+
3 rows in set (0.00 sec)

ORDER BYでは、並べ替えに使う列と向きを指定します。

指定意味
ASC昇順。数値なら小さい順
DESC降順。数値なら大きい順
向きの指定を省略昇順

今回のORDER BYには、priceとproduct_idの2つを書いています。

最初に単価の昇順で並べ、同じ単価の商品がある場合は、商品IDの昇順で並べます。複数の並べ替え条件は、左に書いたものから優先されます。

また、ORDER BYを指定しない場合、結果の並び順は保証されません。表示順を決めたいときは、明示的に指定しましょう。

並べ替えによって変わるのは取得結果の順番であり、商品IDや保存済みの値ではありません。

図3:並べ替えても商品IDは変わらない

この図から分かること

表示位置が変わっても、商品を識別するproduct_idは変わりません。

単価の安い順に並べたとき、クリアファイルは先頭に表示されますが、商品IDは3のままです。表示順と商品を識別する番号は、別のものとして考えましょう。

登録件数と在庫履歴を確認しよう

最後に、productsの商品数を確認します。

SELECT COUNT(*) AS product_count
FROM products;
実行結果の例
+---------------+
| product_count |
+---------------+
|             3 |
+---------------+
1 row in set (0.01 sec)

最初のINSERTで1件、次のINSERTで2件を登録したので、合計3件です。

COUNT(*)で数えているのは商品の行数です。在庫の合計個数ではありません。

続けて、stock_historyの件数も確認してみましょう。

SELECT COUNT(*) AS history_count
FROM stock_history;
実行結果の例
+---------------+
| history_count |
+---------------+
|             0 |
+---------------+
1 row in set (0.00 sec)

商品を登録しただけなので、在庫履歴はまだ0件です。

今回の操作後の状態は、次のようになります。

確認項目状態
登録済みの商品数3件
各商品の在庫数0個
登録済みの在庫履歴0件

外部キーを設定していても、商品登録と同時に履歴が自動作成されるわけではありません。

今回は商品の基本情報を登録しました。今後、入庫や出庫を行うときには、在庫数の更新と履歴の追加を組み合わせていきます。

登録や表示でつまずいたときは

状況確認すること
SQLの構文エラーになるカンマ、丸括弧、文字列の引用符、末尾のセミコロンを確認する
列の数と値の数が合わないINSERTの列名と、VALUESの値を1つずつ対応させる
単価のCHECK制約に違反する負の単価を指定していないか確認する
商品数が想定より多いINSERTを繰り返し実行していないか確認する
商品IDが例と異なるSELECTで実際のIDを確認する
SELECTの結果が0件になるWHEREの条件と、保存されている値を確認する
日本語が文字化けする端末、接続、SQLファイルを使う場合はその文字コードも確認する

登録結果を見直したいときは、INSERTを再実行するのではなく、SELECTで確認しましょう。

また、商品名が同じでも、商品IDが異なれば別の行です。名前だけで同じ商品だと決めつけず、product_idも確認する習慣を付けておくと、後の更新や削除を正確に行いやすくなります。

次は登録した商品を変更・削除しよう

次の記事では、今回登録した商品を使って、UPDATEによる変更とDELETEによる削除を学びます。

どの商品を操作するのかを決めるWHERE条件が、さらに重要になります。まずSELECTで対象を確認する流れを使いながら、データの変更へ進んでいきましょう。

Follow me!