我可以使用MYSQLI和PHP将多个值绑定为单个参数吗?

时间:2010-09-20 16:07:43

标签: php sql mysql mysqli

想象一下,我有以下SQL查询:

SELECT id,name FROM user WHERE id IN ('id1','id2','id3')

现在想象一下我需要PHP提供的id数组。所以我有这样的事情:

$idList = array('id1','id2','id3');
$query = "SELECT id,name FROM user WHERE id IN (?)";
$stmt = $db->prepare($query);
$stmt->bind_param(/*Something*/);

我可以用/*Something*/取代什么来获得与原始查询相同的结果?或者我是否需要在查询格式中输入3个问号?我不想这样做的唯一原因是因为问号的数量是可变的,所以我必须手动构建查询字符串。

4 个答案:

答案 0 :(得分:4)

您可以使用PHP使用?写出占位符str_repeat(),然后只循环bind_param所有参数。

请注意str_repeat将返回的尾随逗号。可以rtrim()使用array_fill()代替join()创建重复占位符数组,然后使用$arrPlaceholders = array_fill(0, count($idList), '?') ; $strPlaceholders = join(', ', $arrPlaceholders) ; 创建占位符字符串。

$query = "SELECT id,name FROM user WHERE id IN ($strPlaceholders)";

然后您的查询可以是:

{{1}}

您可以在循环中绑定参数。

答案 1 :(得分:1)

  

我可以将多个值绑定为一个值   参数使用MYSQLI和PHP?

不,你不能。

根据您的情况,您应该以编程方式构建查询字符串。如果保证它总是三个值,你可以向SQL添加三个标记,然后通过循环遍历数组进行绑定。

答案 2 :(得分:1)

这可能有点旧,但我自己也在想这个。所以我进行了基准测试。首先,我创建了一个简单的表:

SELECT * from random LIMIT 10;
+----+------------+
| id | rand_stuff |
+----+------------+
|  1 | 1988585319 | 
|  2 | 1926594853 | 
|  3 |  820681972 | 
|  4 |  950331574 | 
|  5 |  540721998 | 
|  6 | 1284256353 | 
|  7 |   12804417 | 
|  8 | 2130482967 | 
|  9 | 2018786156 | 
| 10 |  285818156 | 
+----+------------+

SELECT count(id) from random;
+-----------+
| count(id) |
+-----------+
|   3365586 | 
+-----------+

/var/lib/mysql/benchmark# ls -laFh
total 101M
drwx------ 2 mysql mysql 4.0K 2011-05-28 00:06 ./
drwxr-xr-x 7 mysql mysql 4.0K 2011-05-27 23:53 ../
-rw-rw---- 1 mysql mysql   65 2011-05-27 23:53 db.opt
-rw-rw---- 1 mysql mysql 8.4K 2011-05-28 00:06 random.frm
-rw-rw---- 1 mysql mysql  55M 2011-05-28 00:32 random.MYD
-rw-rw---- 1 mysql mysql  47M 2011-05-28 00:32 random.MYI

它是一个重量仅为100 MB的微不足道的结构。随机数是使用php的mt_rand()函数创建的。

这是“Fetch.php”:

<?php

$loops = $argv[1];

$mysqli = new mysqli("localhost", "bench", "bench", "benchmark");
if(mysqli_connect_errno()){
    printf("Connect Failed: %s\n", mysqli_connect_error());
    exit();
}

if($stmt = $mysqli->prepare("SELECT rand_stuff FROM random WHERE id = ?")){
    for($i=1; $i<$loops; $i++){
        $stmt->bind_param("i", $i) or die;
        $stmt->execute() or die;
        $stmt->bind_result($value) or die;
        $stmt->fetch();      
        echo "$i \t $value\n";
    }
    $stmt->close();
}

还有一些基准:

$time php fetch.php 10 > /dev/null

real    0m0.043s
user    0m0.024s
sys 0m0.012s

$ time php fetch.php 100 > /dev/null

real    0m0.057s
user    0m0.044s
sys 0m0.000s

$ time php fetch.php 1000 > /dev/null

real    0m0.166s
user    0m0.080s
sys 0m0.012s

$ time php fetch.php 10000 > /dev/null

real    0m1.083s
user    0m0.412s
sys 0m0.124s

这是fetch2.php

<?php

$loops = $argv[1];

$mysqli = new mysqli("localhost", "bench", "bench", "benchmark");
if(mysqli_connect_errno()){
    printf("Connect Failed: %s\n", mysqli_connect_error());
    exit();
}

$array = array();

for($i=1; $i<$loops; $i++){
    $array[] = $i;
}

$joined_array = join($array, ',');

$results = $mysqli->query("SELECT id, rand_stuff FROM random WHERE id IN ($joined_array)");

while($row = $results->fetch_row()){
    $val1 = $row[0];
    $val2 = $row[1];
    echo "$val1\t$val2\n";
}

以下是相关的基准测试。

$time php fetch2.php 10 > /dev/null

real    0m0.037s
user    0m0.028s
sys 0m0.008s

$time php fetch2.php 100 > /dev/null

real    0m0.044s
user    0m0.032s
sys 0m0.008s

$ time php fetch2.php 1000 > /dev/null

real    0m0.050s
user    0m0.036s
sys 0m0.016s


$ time php fetch2.php 10000 > /dev/null
real    0m0.117s
user    0m0.088s
sys 0m0.024s

并排,我们得到这个表(Fetch.php是“WHERE id =?”和预处理语句,而Fetch2.php在哑查询中使用“WHERE x IN()”语法):

+--------+-----------+------------+
|  Loop  | Fetch.php | Fetch2.php |
+--------+-----------+------------+
| 10     |  .043s    |  .037s     |
| 100    |  .057s    |  .044s     |
| 1000   |  .116s    |  .050s     |
| 10000  | 1.083s    |  .117s     |
+--------+-----------+------------+

显然,“Fetch2.php”效率更高,但在这个基准测试中......在你进入100+元素范围之前,这似乎并不重要。迭代准备好的语句简单而安全(根本没有SQL注入的机会),并且在~10个元素范围内似乎没有慢得多。用~10个元素重复测试有时可以让“Fetch.php”赢得基准。总的来说,Fetch2.php当然赢了,但他们肯定接近这个范​​围。

我倾向于说...如果你的元素少于100个,只需利用预备语句并重复执行即可。这就是准备好的陈述毕竟是为了设计的。当然,没有什么比数据库单轮访问更好,但准备好的声明方法可能具有可接受的性能。当然,在您自己的系统上进行基准测试。最有可能的是,上面的测试太简单了(没有任何连接或子查询......并且db与php脚本位于同一系统上......)

答案 3 :(得分:0)

implode将是最简单的解决方案

$idList = array('id1','id2','id3');
$query = "SELECT id,name FROM user WHERE id IN (?)";
$stmt = $db->prepare($query);
$_param = is_array($idList) ? implode(',',$idList) : $idList;
$stmt->bind_param(1, $_param);