想象一下,我有以下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个问号?我不想这样做的唯一原因是因为问号的数量是可变的,所以我必须手动构建查询字符串。
答案 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);