# ch07 — fetch のモード

Source: https://php-school.pages.dev/topics/db/ch07-fetch-modes/
Site: AIと学ぶPHPの学校 (https://php-school.pages.dev)
Lesson: データベース連携
Level: L4

Reference (official): https://www.php.net/manual/ja/book.pdo.php

## 本文

# ch07 — fetch のモード

## 概要

SELECT で取り出した結果セットの **読み出し方** には、目的別にいくつか手段がある。ここまでは `fetchAll()` だけ使ってきたが、PDO には用途別の関数があり、適切に選ぶとコードが短くなりメモリも節約できる。

主要な顔ぶれは 3 つ。`fetchAll(PDO::FETCH_ASSOC)` は **全行を連想配列の配列** で取る。`fetch()` は 1 回ごとに **1 行だけ** 取り出すループ用で、`while ($row = $stmt->fetch())` の形で何万件にも対応できる (全件をメモリに載せない)。`fetchColumn()` は最初の列の **単一値** を返す関数で、`COUNT(*)` などの集計や 1 項目取得にぴったり。

`fetchAll` の **FETCH モード** には `FETCH_ASSOC` (連想配列) / `FETCH_NUM` (数値添字) / `FETCH_OBJ` (オブジェクト) などがあり、実務では `FETCH_ASSOC` 固定が多い。意識すべきは「**件数が多いときは fetch でストリーミング**」「**単一値は fetchColumn**」の使い分け。

## 学習目標

- `fetchAll(PDO::FETCH_ASSOC)` で全件を **連想配列の配列** で取れる
- `fetch()` で 1 件ずつ取り出すループが書ける
- `fetchColumn()` で `COUNT(*)` などの **単一値** を取れる
- FETCH モードを目的別に使い分けられる

## 所要時間

スライド 4 分 + ドリル 2 問 = **15 分**

## ドリル

| no | 内容 |
|---|---|
| 01 | fetchAll(PDO::FETCH_ASSOC) で全件取得して表示 |
| 02 | fetchColumn で COUNT(*) の単一値を取得 |

## スライド

---
marp: true
theme: dojo
paginate: true
size: 16:9
---

<!--
LLM_CONTEXT:
  Lesson 11 / Chapter 7
  目的: fetchAll / fetch / fetchColumn と FETCH_ASSOC モードを使い分けられる
  扱わない: トランザクション (ch08) / SQL インジェクション (ch09) / オブジェクト fetch (発展)
  読み上げ時間目安: 3 分半〜4 分
-->

# fetch のモード

Lesson 11 / Chapter 7

---

## 取り出し方は 3 種類ある

| 関数 | 戻り値 | 用途 |
|------|--------|------|
| `fetchAll()` | 行の配列 | 全件まとめて欲しい |
| `fetch()` | 1 行 (なければ false) | ループで 1 件ずつ処理 |
| `fetchColumn()` | スカラ値 | COUNT(*) など 1 値だけ欲しい |

---

## `fetchAll(PDO::FETCH_ASSOC)` — 全件・連想配列

```php
<?php
$stmt = $pdo->query("SELECT id, name FROM users ORDER BY id");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

foreach ($rows as $row) {
    echo "{$row['id']}: {$row['name']}\n";
}
```

- 戻り値は `[['id' => 1, 'name' => '太郎'], ...]`
- `FETCH_ASSOC` を付けると **連想配列だけ** (数値キーが消えるのでメモリ節約)

---

## `fetch()` — 1 件ずつループ

```php
<?php
$stmt = $pdo->query("SELECT id, name FROM users ORDER BY id");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    echo "{$row['id']}: {$row['name']}\n";
}
```

- 1 行ずつ返す。なくなったら `false`
- `while` で回すパターンが定番
- 件数が多いとき `fetchAll` よりメモリに優しい

---

## `fetchColumn()` — 1 つの値だけ欲しい

```php
<?php
$stmt = $pdo->query("SELECT COUNT(*) FROM users");
$count = $stmt->fetchColumn();
echo "件数: {$count}\n";
```

- 1 行目の **1 列目だけ** を取る
- `COUNT(*)`・`MAX(age)`・`SUM(price)` のような集計に最適
- 連想配列を経由しないので `$rows[0]['COUNT(*)']` みたいな冗長な書き方が要らない

---

## 使い分けの目安

- **件数が少ない・全部まとめて返したい** → `fetchAll(PDO::FETCH_ASSOC)`
- **大量データ・1 件ずつ処理して捨てる** → `while ($row = $stmt->fetch(...))`
- **集計値が 1 つ欲しい** → `fetchColumn()`

---

## このチャプターでできるようになること

✅ `fetchAll(PDO::FETCH_ASSOC)` で全件を連想配列の配列として取れる
✅ `fetch()` を while で回して 1 件ずつ処理できる
✅ `fetchColumn()` で COUNT(*) のような単一値を取れる
✅ 目的に応じて 3 つを使い分けられる

→ ドリルへ
