IDの配列が$galleries = array(1,2,5)
の場合、WHERE句で配列の値を使用するSQLクエリが必要です。
SELECT *
FROM galleries
WHERE id = /* values of array $galleries... eg. (1 || 2 || 5) */
MySQLで使用するためにこのクエリ文字列をどのように生成できますか?
注意してください。 この回答には深刻な SQLインジェクション の脆弱性が含まれています。外部入力がサニタイズされていることを確認せずに、ここに示されているコードサンプルを使用しないでください。
$ids = join("','",$galleries);
$sql = "SELECT * FROM galleries WHERE id IN ('$ids')";
PDOを使う: [1]
$in = join(',', array_fill(0, count($ids), '?'));
$select = <<<SQL
SELECT *
FROM galleries
WHERE id IN ($in);
SQL;
$statement = $pdo->prepare($select);
$statement->execute($ids);
MySQLiを使う [2]
$in = join(',', array_fill(0, count($ids), '?'));
$select = <<<SQL
SELECT *
FROM galleries
WHERE id IN ($in);
SQL;
$statement = $mysqli->prepare($select);
$statement->bind_param(str_repeat('i', count($ids)), ...$ids);
$statement->execute();
$result = $statement->get_result();
説明:
IN()
演算子を使用します。一般的にそれはこのようになります:
expr IN (value,...)
配列から()
の内側に配置する式を構築できます。括弧内に少なくとも1つの値がなければならないことに注意してください。そうしないと、MySQLはエラーを返します。これは、入力配列に少なくとも1つの値があることを確認することと同じです。 SQLインジェクション攻撃を防ぐために、まず各入力項目に対して?
を生成してパラメータ化クエリを作成します。ここで私はあなたのIDを含む配列が$ids
であると仮定します:
$in = join(',', array_fill(0, count($ids), '?'));
$select = <<<SQL
SELECT *
FROM galleries
WHERE id IN ($in);
SQL;
3つの項目の入力配列が与えられたとすると$select
は次のようになります。
SELECT *
FROM galleries
WHERE id IN (?, ?, ?)
繰り返しになりますが、入力配列の各項目には?
があります。その後、PDOまたはMySQLiを使用して、上記のようにクエリを準備して実行します。
IN()
演算子を使うバインドパラメータのため、文字列と整数を簡単に変更できます。 PDOの場合、変更は必要ありません。 MySQLiでは、文字列をチェックする必要がある場合はstr_repeat('i',
をstr_repeat('s',
に変更します。
[1]: 簡潔にするためにエラーチェックを省略しました。データベースメソッドごとに通常のエラーをチェックする必要があります(または、DBドライバが例外をスローするように設定します)。
[2]: PHP 5.6以上が必要です。簡潔さのためにエラーチェックを省略しました。
int:
$query = "SELECT * FROM `$table` WHERE `$column` IN(".implode(',',$array).")";
文字列:
$query = "SELECT * FROM `$table` WHERE `$column` IN('".implode("','",$array)."')";
事前に入力を正しくサニタイズすると仮定します。
$matches = implode(',', $galleries);
次に、クエリを調整してください。
SELECT *
FROM galleries
WHERE id IN ( $matches )
データセットに応じて適切に値を見積もります。
つかいます:
select id from galleries where id in (1, 2, 5);
単純なfor each
ループが機能します。
Flavius/AvatarKavaの方法 が優れていますが、配列の値にコンマが含まれていないことを確認してください。
Flavius Stefの答え として、すべてのid
がint値であることを確認するためにintval()
を使用できます。
$ids = join(',', array_map('intval', $galleries));
$sql = "SELECT * FROM galleries WHERE id IN ($ids)";
MySQLi の場合/エスケープ機能付き:
$ids = array_map(function($a) use($mysqli) {
return is_string($a) ? "'".$mysqli->real_escape_string($a)."'" : $a;
}, $ids);
$ids = join(',', $ids);
$result = $mysqli->query("SELECT * FROM galleries WHERE id IN ($ids)");
準備済みステートメントのあるPDOの場合
$qmarks = implode(',', array_fill(0, count($ids), '?'));
$sth = $dbh->prepare("SELECT * FROM galleries WHERE id IN ($qmarks)");
$sth->execute($ids);
SQLインジェクションの脆弱性と空の状態に注意を払う必要があります。私は両方を以下のように扱うつもりです。
純粋な数値配列の場合は、各要素に対して適切な型変換viz intval
またはfloatval
またはdoubleval
を使用します。文字列型の場合は mysqli_real_escape_string()
必要に応じて数値にも適用できます。 MySQLでは数字だけでなく日付の変種も文字列として使用できます。
クエリに渡す前に値を適切にエスケープするには、次のような関数を作成します。
function escape($string)
{
// Assuming $db is a link identifier returned by mysqli_connect() or mysqli_init()
return mysqli_real_escape_string($db, $string);
}
そのような関数はあなたのアプリケーションですでに利用可能であるか、あるいは既に作成されているかもしれません。
次のように文字列配列をサニタイズします。
$values = array_map('escape', $gallaries);
適切な場合は、代わりにintval
、floatval
、またはdoubleval
を使用して数値配列をサニタイズできます。
$values = array_map('intval', $gallaries);
それから最後にクエリ条件を構築します
$where = count($values) ? "`id` = '" . implode("' OR `id` = '", $values) . "'" : 0;
または
$where = count($values) ? "`id` IN ('" . implode("', '", $values) . "')" : 0;
$galleries = array();
のように配列が空になることもあるので、IN ()
は空のリストを許可しないことに注意してください。代わりにOR
を使うこともできますが、問題は残ります。したがって、上記のチェックcount($values)
は、同じことを確認することです。
そしてそれを最後のクエリに追加します。
$query = 'SELECT * FROM `galleries` WHERE ' . $where;
_ tip _ :すべての行を隠すのではなく、空の配列の場合にすべてのレコードを表示する(フィルタリングしない)場合は、単に 0 を 1 に置き換えます。三項の誤った部分に。
より安全です。
$galleries = array(1,2,5);
array_walk($galleries , 'intval');
$ids = implode(',', $galleries);
$sql = "SELECT * FROM galleries WHERE id IN ($ids)";
入力配列を適切にフィルタリングすれば、この "WHERE id IN"節を使用できます。このようなもの:
$galleries = array();
foreach ($_REQUEST['gallery_id'] as $key => $val) {
$galleries[$key] = filter_var($val, FILTER_SANITIZE_NUMBER_INT);
}
以下の例のように:
$galleryIds = implode(',', $galleries);
すなわち今あなたは安全に$query = "SELECT * FROM galleries WHERE id IN ({$galleryIds})";
を使うべきです
テーブルtexts
(T_ID (int), T_TEXT (text))
とテーブルtest
(id (int), var (varchar(255)))
があるかもしれません
insert into test values (1, '1,2,3') ;
では、以下はテーブルテキストからT_ID IN (1,2,3)
の行を出力します。
SELECT * FROM `texts` WHERE (SELECT FIND_IN_SET( T_ID, ( SELECT var FROM test WHERE id =1 ) ) AS tm) >0
こうすれば、PHPや他のプログラミング言語を使用せずに、追加のテーブルやSQLのみを使用して、単純なn2mデータベース関係を管理できます。
Shrapnel氏の SafeMySQL [PHP用ライブラリは、パラメータ化されたクエリでタイプヒント付きのプレースホルダを提供し、配列を操作するための便利なプレースホルダをいくつか含みます。 ?a
プレースホルダーは、配列をエスケープ文字列*のコンマ区切りリストに展開します。
例えば:
$someArray = [1, 2, 5];
$galleries = $db->getAll("SELECT * FROM galleries WHERE id IN (?a)", $someArray);
* MySQLは自動型強制を実行するので、SafeMySQLが上記のIDを文字列に変換しても問題ありません - それでも正しい結果が得られます。
より多くの例:
$galleryIds = [1, '2', 'Vitruvian Man'];
$ids = array_filter($galleryIds, function($n){return (is_numeric($n));});
$ids = implode(', ', $ids);
$sql = "SELECT * FROM galleries WHERE id IN ({$ids})";
// output: 'SELECT * FROM galleries WHERE id IN (1, 2)'
$statement = $pdo->prepare($sql);
$statement->execute();
INクエリを使用する以外に、INクエリでSQLインジェクションの脆弱性が発生する危険性があるため、2つの方法があります。 looping を使用して正確なデータを取得することも、 _または_ caseを使用してクエリを使用することもできます。
1. SELECT *
FROM galleries WHERE id=1 or id=2 or id=5;
2. $ids = array(1, 2, 5);
foreach ($ids as $id) {
$data[] = SELECT *
FROM galleries WHERE id= $id;
}
元の質問は数値の配列に関するもので、文字列の配列を使用しているため、与えられた例を機能させることはできませんでした。
IN()
関数を使うには、各文字列を一重引用符で囲む必要があることがわかりました。
これが私の解決策です
foreach($status as $status_a) {
$status_sql[] = '\''.$status_a.'\'';
}
$status = implode(',',$status_sql);
$sql = mysql_query("SELECT * FROM table WHERE id IN ($status)");
ご覧のとおり、最初の関数はsingle quotes (\')
内の各配列変数をラップしてから配列を分解します。
注:$status
は、SQLステートメント内に単一引用符を含みません。
引用符を追加するより良い方法がおそらくありますが、これは動作します。
PDOなしで安全な方法:
$ids = array_filter(array_unique(array_map('intval', (array)$ids)));
if ($ids) {
$query = 'SELECT * FROM `galleries` WHERE `id` IN ('.implode(',', $ids).');';
}
(array)$ids
変数$ids
を配列にキャストarray_map
すべての配列値を整数に変換しますarray_unique
繰り返し値を削除array_filter
ゼロ値を削除implode
:IN選択にすべての値を結合します以下は私が使った方法で、PDOを他のデータのための名前付きプレースホルダーと共に使っています。 SQLインジェクションを克服するために、整数値のみを受け入れ、それ以外はすべて拒否するように配列をフィルタリングしています。
$owner_id = 123;
$galleries = array(1,2,5,'abc');
$good_galleries = array_filter($chapter_arr, 'is_numeric');
$sql = "SELECT * FROM galleries WHERE owner=:OWNER_ID AND id IN ($good_galleries)";
$stmt = $dbh->prepare($sql);
$stmt->execute(array(
"OWNER_ID" => $owner_id,
));
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);