Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】PDO::FETCH_UNIQUE定数の使い方

FETCH_UNIQUE定数の使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

FETCH_UNIQUE定数は、データベースからデータを取得する際の挙動を制御する、PHP Data Objects (PDO) 拡張機能が提供する定数の一つです。この定数は、主にPDOStatement::fetchAll()メソッドなどでクエリ結果を配列として取り出す際に、データの重複を排除し、一意な値のみを保持するよう指定するために使用されます。

具体的には、結果セットから取得されるデータにおいて、重複する値が検出された場合、最初の出現のみが採用され、それ以降の重複する値は無視される仕組みです。特にPDO::FETCH_GROUP定数と組み合わせて使用されることが多く、この組み合わせでは、最初に指定されたカラムの値をキーとしてデータをグループ化し、さらにその各グループ内で値の重複を排除して、一意なデータのみを抽出する働きをします。

例えば、ある特定の情報について、重複する複数のレコードが存在する場合でも、最も代表的または最初のデータのみを取得したい場合に非常に役立ちます。これにより、取得したデータの一貫性を保ちながら、効率的に情報を整形することが可能です。単独で使うことも可能ですが、PDO::FETCH_GROUPなどの他のフェッチモード定数とビットOR演算子 | を使って組み合わせることで、その真価をより発揮します。データベースからの情報取得において、重複するデータの管理をシンプルにするための重要な定数です。

構文(syntax)

1<?php
2
3// PDOデータベース接続を確立済みとします
4$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'username', 'password');
5
6// データベースからデータを取得するステートメントを実行します
7// この例では、重複する 'name' を含む可能性のある users テーブルを想定しています
8$stmt = $pdo->query('SELECT id, name FROM users ORDER BY name');
9
10// PDO::FETCH_UNIQUE を使用して、結果セットから重複する行を排除し、
11// さらに PDO::FETCH_ASSOC を指定して連想配列として結果を取得します。
12$uniqueUsers = $stmt->fetchAll(PDO::FETCH_ASSOC | PDO::FETCH_UNIQUE);
13
14// $uniqueUsers 配列には、重複する 'name' の行が一つにまとめられた結果が格納されます。
15
16?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

int

PDO::FETCH_UNIQUE は、PDOStatement::fetch() または PDOStatement::fetchAll() メソッドで使用される定数です。この定数を指定すると、取得した結果セットの各行から、指定された列の値が重複しないように、その値だけをキーとした配列が返されます。

サンプルコード

PHP PDO::FETCH_UNIQUE でユニークなデータを取得する

1<?php
2
3/**
4 * PDO::FETCH_UNIQUE 定数を使用して、データベースからユニークなキーを持つデータをフェッチする方法を示します。
5 *
6 * PDO::FETCH_UNIQUE は、結果セットの最初のカラムの値をキーとして、連想配列を生成します。
7 * キーが重複する場合、後から見つかった行が前の行を上書きするため、
8 * 各キーに対しては結果セット中の最後の行(デフォルトのソート順、またはORDER BY句によって決まる順序)のみが残ります。
9 *
10 * @return void
11 */
12function demonstratePdoFetchUnique(): void
13{
14    try {
15        // 1. SQLite インメモリデータベースへの接続
16        //    データベースファイルを物理的に作成しないため、テストや学習に最適です。
17        $pdo = new PDO('sqlite::memory:');
18        // エラーモードを例外に設定し、データベース操作でエラーが発生した場合にPDOExceptionをスローさせます。
19        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
20
21        // 2. テスト用のテーブルを作成
22        //    'category_name' を最初のカラムに配置し、PDO::FETCH_UNIQUE のキーとして使用します。
23        $pdo->exec("
24            CREATE TABLE IF NOT EXISTS products (
25                id INTEGER PRIMARY KEY AUTOINCREMENT,
26                category_name TEXT NOT NULL,
27                product_name TEXT NOT NULL
28            );
29        ");
30
31        // 3. サンプルデータを挿入
32        //    'Fruit' と 'Vegetable' のカテゴリ名を意図的に重複させます。
33        //    これにより、PDO::FETCH_UNIQUE が重複するキーをどのように扱うかを確認できます。
34        $productsData = [
35            ['Fruit', 'Apple'],
36            ['Vegetable', 'Carrot'],
37            ['Fruit', 'Banana'],    // 'Fruit' カテゴリの重複 (前の'Apple'を上書きする可能性)
38            ['Vegetable', 'Potato'], // 'Vegetable' カテゴリの重複 (前の'Carrot'を上書きする可能性)
39            ['Dairy', 'Milk'],
40            ['Fruit', 'Orange']     // 'Fruit' カテゴリの再度の重複 (前の'Banana'を上書きする可能性)
41        ];
42
43        $stmt = $pdo->prepare("INSERT INTO products (category_name, product_name) VALUES (?, ?)");
44        foreach ($productsData as $data) {
45            $stmt->execute($data);
46        }
47
48        // 4. PDO::FETCH_UNIQUE を使用してデータをフェッチ
49        //    SELECT句で 'category_name' を最初に指定することが重要です。
50        //    ORDER BY id ASC を指定することで、最も大きいIDを持つ(最も後に挿入された)行が最終的に残ります。
51        $stmt = $pdo->query("SELECT category_name, product_name, id FROM products ORDER BY id ASC");
52        $uniqueProducts = $stmt->fetchAll(PDO::FETCH_UNIQUE);
53
54        echo "PDO::FETCH_UNIQUE を使用してフェッチした結果:\n";
55        echo "------------------------------------------------\n";
56        print_r($uniqueProducts);
57        echo "------------------------------------------------\n";
58        // 出力例:
59        // Array
60        // (
61        //     [Fruit] => Array
62        //         (
63        //             [0] => Orange
64        //             [1] => 7
65        //         )
66        //     [Vegetable] => Array
67        //         (
68        //             [0] => Potato
69        //             [1] => 4
70        //         )
71        //     [Dairy] => Array
72        //         (
73        //             [0] => Milk
74        //             [1] => 5
75        //         )
76        // )
77        // 説明:
78        // 'Fruit' カテゴリには 'Apple', 'Banana', 'Orange' が挿入されましたが、
79        // 最終的に最も大きなIDを持つ 'Orange' のデータが残っています。
80        // 同様に 'Vegetable' カテゴリには 'Carrot' と 'Potato' が挿入されましたが、
81        // 最終的に最も大きなIDを持つ 'Potato' のデータが残っています。
82        // 'Dairy' カテゴリは重複がなかったため、そのまま残っています。
83
84    } catch (PDOException $e) {
85        // データベース関連のエラーが発生した場合の処理
86        error_log("データベースエラー: " . $e->getMessage());
87        echo "データベース処理中にエラーが発生しました。詳細はログをご確認ください。\n";
88    } catch (Exception $e) {
89        // その他の予期せぬエラーが発生した場合の処理
90        error_log("予期せぬエラー: " . $e->getMessage());
91        echo "予期せぬエラーが発生しました。詳細はログをご確認ください。\n";
92    }
93}
94
95// 関数を実行します。
96demonstratePdoFetchUnique();

PDO::FETCH_UNIQUEは、PHPでデータベースからデータを取得する際に、取得結果を特定の形式の配列として整理するために使用される定数です。この定数を指定してデータをフェッチすると、結果セットの最初のカラムの値をキーとして、PHPの連想配列が生成されます。

この定数の重要な特徴は、キーが重複する場合の挙動にあります。もし同じキーを持つ行が複数存在した場合、PDO::FETCH_UNIQUE後から見つかった行のデータで以前の行のデータを上書きします。これにより、各キーに対しては、結果セット中で最後に処理された行のデータのみが最終的に残る形となります。どの行が「最後」になるかは、SQLクエリに含めるORDER BY句などでデータのソート順を指定することで制御可能です。例えば、更新日時やIDの昇順でソートすれば、最も新しいデータがそのキーの最終的な値として採用されます。

この定数自体は、メソッドのように引数を取ることはなく、PHPの内部で特定の意味を持つ整数値(int)として定義されています。特定のカテゴリや識別子に紐づく、最新または特定の1件のデータだけを効率的に取得して配列として扱いたい場合に非常に有用です。

PDO::FETCH_UNIQUEを使用する際は、SELECT文でキーとしたいカラムを必ず最初に指定してください。この定数は、結果セットの最初のカラムの値をキーとして連想配列を生成し、キーが重複する場合は、後から見つかった行が前の行を上書きします。どの行が最終的に残るかはSQLのORDER BY句によって決まるため、意図した結果を得るために適切に記述することが重要です。サンプルではORDER BY id ASCにより、より新しいデータが優先されています。また、データベース操作ではPDO::ATTR_ERRMODEをPDO::ERRMODE_EXCEPTIONに設定し、try-catchブロックで例外を捕捉し、エラー処理を適切に行うことが安全なコード運用の基本です。

関連コンテンツ