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

C言語+MySQL入門|商品を登録・表示する
これまでの記事で、商品テーブルのproductsと在庫履歴テーブルのstock_historyを作成し、外部キーで関連付けました。
今回は、productsに実際の商品を登録し、保存されたデータを表示します。データを追加するINSERTと、データを取得するSELECTを使って、テーブルを操作してみましょう。
この記事では、次の内容を学びます。
- INSERTで商品を1件登録する。
- 自動採番された商品IDと、列の初期値を確認する。
- 複数の商品をまとめて登録する。
- SELECTで表示する列や行を選ぶ。
- ORDER BYで表示順を指定する。
ここで使うSQLは、後でCプログラムから商品を登録・表示するときにも基本となります。まずはMySQLクライアントから実行し、SQLと結果の対応を確認していきましょう。
今回登録する商品を確認しよう
今回は、次の3つの商品を登録します。
| 商品名 | 単価 | 登録時の在庫数 |
|---|---|---|
| ノート | 180.00 | 0 |
| ボールペン | 120.00 | 0 |
| クリアファイル | 90.00 | 0 |
この記事では、商品の基本情報を登録するところから始めるため、在庫数はすべて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 products | productsへ新しい行を追加する |
| product_name, price | 値を指定する列を、この順番で並べる |
| VALUES | 登録する値を指定する |
| ノート | product_nameに保存する文字列 |
| 180.00 | priceに保存する数値 |
列名と値は、左から順に対応します。
今回の列の並びは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_id | product_name | price | stock | created_at |
|---|---|---|---|---|
| 1 | ノート | 180.00 | 0 | 2026-10-04 10:00:00 |
created_atには、実際に登録した日時が表示されます。表の日時は例です。
各部分の意味を確認しましょう。
| SQLの部分 | 意味 |
|---|---|
| SELECT * | すべての列を取得する |
| FROM products | productsからデータを取得する |
| 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: 02 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_id | product_name | price | stock |
|---|---|---|---|
| 1 | ノート | 180.00 | 0 |
| 2 | ボールペン | 120.00 | 0 |
| 3 | クリアファイル | 90.00 | 0 |
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で対象を確認する流れを使いながら、データの変更へ進んでいきましょう。










