Passing an array to a query using a WHERE clause

2018-12-31 01:32发布

Given an array of ids $galleries = array(1,2,5) I want to have a SQL query that uses the values of the array in its WHERE clause like:

SELECT *
FROM galleries
WHERE id = /* values of array $galleries... eg. (1 || 2 || 5) */

How can I generate this query string to use with MySQL?

标签: php mysql arrays
18条回答
其实,你不懂
2楼-- · 2018-12-31 02:23

We should take care of SQL injection vulnerabilities and an empty condition. I am going to handle both as below.

For a pure numeric array, use the appropriate type conversion viz intval or floatval or doubleval over each element. For string types mysqli_real_escape_string() which may also be applied to numeric values if you wish. MySQL allows numbers as well as date variants as string.

To appropriately escape the values before passing to the query, create a function similar to:

function escape($string)
{
    // Assuming $db is a link identifier returned by mysqli_connect() or mysqli_init()
    return mysqli_real_escape_string($db, $string);
}

Such a function would most likely be already available to you in your application, or maybe you've already created one.

Sanitize the string array like:

$values = array_map('escape', $gallaries);

A numeric array can be sanitized using intval or floatval or doubleval instead as suitable:

$values = array_map('intval', $gallaries);

Then finally build the query condition

$where  = count($values) ? "`id` = '" . implode("' OR `id` = '", $values) . "'" : 0;

or

$where  = count($values) ? "`id` IN ('" . implode("', '", $values) . "')" : 0;

Since the array can also be empty sometimes, like $galleries = array(); we should therefore note that IN () does not allow for an empty list. One can also use OR instead, but the problem remains. So the above check, count($values), is to ensure the same.

And add it to the final query:

$query  = 'SELECT * FROM `galleries` WHERE ' . $where;

TIP: If you want to show all records (no filtering) in case of an empty array instead of hiding all rows, simply replace 0 with 1 in the ternary's false part.

查看更多
余生无你
3楼-- · 2018-12-31 02:26

Col. Shrapnel's SafeMySQL library for PHP provides type-hinted placeholders in its parametrised queries, and includes a couple of convenient placeholders for working with arrays. The ?a placeholder expands out an array to a comma-separated list of escaped strings*.

For example:

$someArray = [1, 2, 5];
$galleries = $db->getAll("SELECT * FROM galleries WHERE id IN (?a)", $someArray);

* Note that since MySQL performs automatic type coercion, it doesn't matter that SafeMySQL will convert the ids above to strings - you'll still get the correct result.

查看更多
何处买醉
4楼-- · 2018-12-31 02:28

Using 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);

Using 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();

Explanation:

Use the SQL IN() operator to check if a value exists in a given list.

In general it looks like this:

expr IN (value,...)

We can build an expression to place inside the () from our array. Note that there must be at least one value inside the parenthesis or MySQL will return an error; this equates to making sure that our input array has at least one value. To help prevent against SQL injection attacks, first generate a ? for each input item to create a parameterized query. Here I assume that the array containing your ids is called $ids:

$in = join(',', array_fill(0, count($ids), '?'));

$select = <<<SQL
    SELECT *
    FROM galleries
    WHERE id IN ($in);
SQL;

Given an input array of three items $select will look like:

SELECT *
FROM galleries
WHERE id IN (?, ?, ?)

Again note that there is a ? for each item in the input array. Then we'll use PDO or MySQLi to prepare and execute the query as noted above.

Using the IN() operator with strings

It is easy to change between strings and integers because of the bound parameters. For PDO there is no change required; for MySQLi change str_repeat('i', to str_repeat('s', if you need to check strings.

[1]: I've omitted some error checking for brevity. You need to check for the usual errors for each database method (or set your DB driver to throw exceptions).

[2]: Requires PHP 5.6 or higher. Again I've omitted some error checking for brevity.

查看更多
浅入江南
5楼-- · 2018-12-31 02:28

More an example:

$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();
查看更多
君临天下
6楼-- · 2018-12-31 02:30

BEWARE! This answer contains a severe SQL injection vulnerability. Do NOT use the code samples as presented here, without making sure that any external input is sanitized.

$ids = join("','",$galleries);   
$sql = "SELECT * FROM galleries WHERE id IN ('$ids')";
查看更多
柔情千种
7楼-- · 2018-12-31 02:32

Use:

select id from galleries where id in (1, 2, 5);

A simple for each loop will work.

Flavius/AvatarKava's way is better, but make sure that none of the array values contain commas.

查看更多
登录 后发表回答