2009-10-25 11 views
8

私はPHP/PDOで準備文を使って遊んでいます。私は、フィールド名の変数を渡す必要がある状況があるしかしPDOプリペアドステートメントでどのトークンをパラメータ化できますか?

$stmt = $db->prepare('SELECT title FROM episode WHERE id=:id'); 
$stmt->bindParam(':id', $id, PDO::PARAM_INT); 
$id = 5; 
$stmt->execute(); 

:基本的なクエリは、WHERE句に値を渡して、正常に動作します。 (適切なバインディングを持つ)このクエリは、正常に動作します:

SELECT :field FROM episode WHERE id=:id 

この1つはエラーを与える:この1つはエラーを与えるものではありません

SELECT title FROM :field WHERE id=:id 

が、行が戻されない:

SELECT title FROM episode WHERE :field=:id 

したがって、準備された声明ではどのようなことが有効でしょうか?フィールド名やテーブル名などをパラメータ化できますか?

答えて

10

IN句のテーブル名、カラム名、または何かをパラメータ化することはできません(pointing out the IN clause restrictionの場合はc0r0nerのおかげで)。

this questionおよびその後にthis comment in the PHP manualを参照してください。思考は、特にデータベースで表現ダイナミックなツリー構造のために、非常に制限的である(と私の意見で堅牢なソリューションを実装するのが面倒であることのためだけの言い訳である)ことジョシュLeitzel

@

+0

お返事ありがとうございます。投稿した最初のクエリがうまくいかないことが判明しました。例えば、 '' title''を ':field'にバインドすると、フィールドの値ではなく 'title'という文字列が選択されます。 PDOが私のために扱うはずのセキュリティを追加する必要があるので、今やカラム/テーブルをバインドする方法がないというのは奇妙なことです。/ – DisgruntledGoat

+0

これは背後にある考え方ではおそらく、ユーザーは、クエリが呼び出すフィールド/テーブルを直接選択します。しかし、私はそれがあなたの最後に少し余分な作業を追加することに同意します。 –

+0

私はあなたのポイントを見ます。しかし、私はテーブルを指定するだけの状況で使用していますが、抽象的な方法で(例: 'displayTable( 'エピソード')'。私はこの場合、パラメータ/セキュリティについて本当に心配する必要はないと思う。 – DisgruntledGoat

1

は、次の例を考えてみましょう:

会社の階層は、エンティティの用語で表現されています

私のプロジェクトでは、論理的な構造を有しています。各エンティティは、階層のメンバーである一般的なケースで、または階層の特定のレベルのメンバーとして扱うことができます。

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 

これは以下のフラット表現が生成されることになる:次の具体例は、私は何を意味するか示すdivision_idを有するであろう分割レベルである

entity_tree (
    entity_id 
    division_id 
    area_id 
    store_id 
) 

エンティティをAREA_IDおよびNULLとしてSTORE_ID 、領域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); 
} 

を、唯一のプリペアドステートメント。

例全体では、ユーザー入力はまったく使用されません。

ちょっと考えてください。

+0

何がポイントですか?このインスタンスでは、ユーザー入力がないため、通常の変数を簡単に使用できます。ここに注射する機会はありません。また、OPの質問に対する答えではないので、これは私の答えにコメントとして投稿されているはずです。 (私はあなたがこれに気づくことができなかっただろうと気づきました。) –

1

IN句の中で何もパラメータ化することはできません。

+0

ありがとう、私はそれを忘れました。私はそれを私の答えに加えます。 –

関連する問題