8

ちょっとした問題に直面しています。私は現在、MySQLで動的テーブル名を使用する必要があるアプリケーションに取り組んでいます。

基本的に、私はいくつかの要因(ジャンル、再生時間、リリース日など)に基づいてデータベースからアルバムを選択するプロセスを持っています-このプロセスのセクションには、ユーザーが一連のカスタムフィルターを作成できるようにするセクションがあります。

カスタムフィルターは、その選択基準内のすべてのアルバムのユーザーにカウントを返します。これらのアルバムのIDは、ランダムに生成されたハッシュ/シリアル番号とともにテーブルに保存されます(例:albumSelect_20880f9c05d68a)

巨大なコンマ区切りのリストをフィールドに格納したくなかったので、このようにしました(本当にばかげています)-そして、HTMLの非表示フィールドに値の配列を送信するのは好きではありませんでした。データスループット(一度に数千行になる可能性があります)

CodeIgniterでは、次のようにクエリバインディングを使用してSQLクエリを生成しています。

select * from artists where artistName = ? AND albumTitle = ?

クエリをパラメータ化すると、クエリは自動的にエスケープされます

$query = $this->db->query($sql,array("Singer","Album"));

ここで注意が必要な部分があります

次のようなクエリを作成すると、次のようになります。

$sql = "select albumid from albums where albumid in (select albumid from albumSelect_?)";
$this->db->query($sql,array('20880f9c05d68a'));

結果のクエリは次のようになります。

select `albumid` from `albums` where `albumid` in (select `albumid` from `albumSelect_'20880f9c05d68a'`)

そして、まったく当然のことですが、明らかにクエリは無効です。

編集:詳細

ユーザーが選択する基準によっては、クエリがより大きなクエリの一部になる場合があります。例えば

$sql = "select albumid from albums where albumid in(select albumid from tags where tag = ?) AND albumid in(select albumid from albumSelect_?)";

これを機能させる方法があるのか​​、それとも誰かがより良い代替案を提案できるのか、私はただ疑問に思っていました。テーブル名の連結は明らかにオプションではありません。

前もって感謝します!

デイブ

4

2 に答える 2

1

エスケープメカニズムはデータ文字列専用であり、スキーマ名用ではありません。つまり、テーブルの構造ではなく、テーブルのコンテンツに対してのみです。したがって、文字列を自分でクエリに貼り付けるか、この方法でテーブルを使用しないようにする必要があります。クエリテンプレートのは、そこでは役に立ちません。?

文字列をテーブル名に貼り付けると、通常のPHP文字列連結メカニズムを使用できます。SQLインジェクションを回避するために、文字列を適切に厳密な正規表現と照合するように特に注意する必要があります。生成した形式のランダムな文字列を1つだけ貼り付け、それ以外は貼り付けないようにしてください。

別の方法として、すべての選択を含む1つの大きなテーブルを作成し、追加の列を使用して識別ハッシュを保持するか、その他の適切なキーを使用して単一の選択を識別することができます。そうすれば、通常の操作中にデータベーススキーマを変更する必要がなくなります。私を含め、ほとんどの開発者は、プログラムコードによるそのような変更を避けたいと思っています。優れたデータベース設計は、固定スキーマで機能します。

于 2012-07-18T20:03:17.750 に答える
0

動的SQLを使用したいように思えます。おそらく、プリペアドステートメントのパスをたどる必要があります。それらを使用しPREPAREて、文字列を呼び出し、続いEXECUTEてそれを呼び出すことができます。通常の連結は問題なく機能します。

これにより、SQLを文字列として作成して実行できるようになります。CodeIgniterのパラメーター化をMySQLストアドプロシージャと組み合わせて使用​​する場合は、次のようなクエリを呼び出すことができます(実際のクエリのを含むストアドプロシージャであると"CALL selectAlbums(?, ?)"想定)。これにより、セットが返されます。selectAlbumsPREPARE

'出力のsを削除したい場合は、パラメータをに変換しCONCATます。これにより、通常の文字列が生成されます。

于 2012-07-18T07:28:50.847 に答える