PDO準備済みステートメントでパラメーター化できるトークンはどれですか?
-
06-07-2019 - |
質問
PHP / PDOで準備されたステートメントをいじっています。基本的なクエリは正常に機能し、値をWHERE句に渡します:
$stmt = $db->prepare( 'SELECT title FROM episode WHERE id=:id' );
$stmt->bindParam( ':id', $id, PDO::PARAM_INT );
$id = 5;
$stmt->execute();
ただし、フィールド名に変数を渡す必要がある状況があります。このクエリ(適切なバインディングを使用)は正常に機能します。
SELECT :field FROM episode WHERE id=:id
これはエラーになります:
SELECT title FROM :field WHERE id=:id
これはエラーにはなりませんが、行を返しません:
SELECT title FROM episode WHERE :field=:id
では、準備されたステートメントで何が機能しますか?フィールド名、テーブル名などを「パラメータ化」できますか?
解決
テーブル名、列名、または IN
句でパラメータ化することはできません( IN
句の制限の指摘)。
この質問を参照してください。その後 PHPマニュアルのこのコメント。
他のヒント
@ジョシュライツェル
特にデータベースで表現された動的なツリー構造の場合、その考え方は非常に制限的であり(そして、私の意見では、堅牢なソリューションを実装するには遅すぎるという言い訳にすぎません)。
次の例を検討してください:
私のプロジェクトには論理構造があります:
企業階層は、エンティティの観点から表現されます。各エンティティは、階層のメンバーである一般的な場合、または階層の特定のレベルのメンバーとして扱うことができます。階層自体は、次のようにテーブル内で単一のツリーブランチとして定義されます。
entity_structure (
id
name
parent_entity_structure_id
);
およびエンティティ自体は次のように表されます:
entities (
id
name
entity_structure_id
parent_id
);
使いやすくするために、ツリーの平面図を作成するアルゴリズムを作成しました。次の具体例は、私が何を意味するかを示しています。
SELECT * FROM entity_structure;
id | name | entity_structure_parent_id
-----------------------------------------------------------
1 | Company | null (special one that always exists)
2 | Division | 1
3 | Area | 2
4 | Store | 3
これにより、次のフラットな表現が生成されます。
entity_tree (
entity_id
division_id
area_id
store_id
)
部門レベルのエンティティには、division_id、area_id、store_idがNULL、area area_id、store_idがNULLなどがあります。
これの良い点は、次のようなステートメントを使用して、部門のすべての子を照会できることです:
SELECT * FROM entity_tree WHERE division_id = :division_id;
ただし、これは、クエリしているエンティティの構造レベルを知っていることを前提としています。行うのがいいでしょう:
SELECT * FROM entity_tree WHERE :structure = :entity_id;
単一のエンティティの構造レベルを把握するのが難しくないことは知っていますが、すべてが同じレベルではない可能性があるエンティティのコレクションをループしていると仮定します。今では、階層の各レベルに対して個別のクエリを作成する必要がありますが、フィールドをパラメーター化できる場合は、次の操作を実行できます。
$children = array();
$stmt = $pdo->prepare('SELECT entity_id FROM entity_tree WHERE :structure = :entityId');
foreach ($entities AS $entity) {
$stmt->execute(array(
':structure' = $entity->getEntityStructureId(),
':entityId' = $entity->getId()
));
$children[$entity->getId()] = $stmt->fetchAll(PDO::FETCH_COLUMN);
}
結果として、よりクリーンなコードと1つの準備済みステートメントのみが作成されます。
例全体では、ユーザー入力は一切使用しません。
考慮すべきことがあります。
IN
句内では何もパラメータ化できません。