PHP - 如何在预准备语句中将数组替换为主机参数

时间:2016-04-13 01:16:17

标签: php sql sqlite

我能够绑定intstrboolnull类型的值,但我无法绑定数组类型。
我尝试了两种功能,即bindValuebindParam,但它们都没有奏效。 我怎么能做到这一点?

// a helper function to map Sqlite data type
function getArgType($arg) {
    switch (gettype($arg)) {
        case 'double':  return SQLITE3_FLOAT;
        case 'integer': return SQLITE3_INTEGER;
        case 'boolean': return SQLITE3_INTEGER;
        case 'NULL':    return SQLITE3_NULL;
        case 'string':  return SQLITE3_TEXT;
        default:
            throw new \InvalidArgumentException('Argument is of invalid type '.gettype($arg));
    }
}

$sql = "SELECT * FROM table_name WHERE id IN (?)";
$params = [[10, 9, 6]]; // array of array
$dbpath = '/path/to/sqlite.sqlite';
$db = new SQLite3($dbPath, SQLITE3_OPEN_READONLY);
$stmt = $db->prepare($sql);

try {
    foreach ($params as $index => $val) {
        if (is_array($val)) {
            /************* I am stuck here  *************/
            $ok = $stmt->bindParam($index + 1, $val);
            // Using bindValue also didn't worked!
        } else {
            $ok = $stmt->bindValue($index + 1, $val, getArgType($val));
        }

        if (!$ok) {
            throw new Exception("Unable to bind param: $val");
        }
    }
} catch (Exception $ex) {
    // NO exception is thrown from bindValue() or bindParam()
    $reason = "Error in binding statement. " . $ex->getMessage();
    die($reason);
}

$result = $stmt->execute();
$data = [];
while ($row = $result->fetchArray($mode)) {
    $data[] = $row;
}
var_dump($data);

编辑:我已经尝试用param数组中所需数量的问号替换单个?,但只有当我的数组小于 1000时才能正常工作价值!我认为这是对PHP中SQLite3中语句编写方式的限制。

5 个答案:

答案 0 :(得分:9)

不幸的是,不可能!你不能绑定一个数组。

对您来说最简单的解决方案如下:

  1. 使用数组
  2. 中的每个值创建一个占位符(?)的SQL查询
  3. 通过迭代数组来绑定每个值。
  4. 但还有另一种选择(例如子SELECT)

    More information here(即使它是一个Java问题,它几乎是相同的主题/问题,因为数据库类型在这种情况下并不重要)

    编辑:通常,绑定参数的SQL限制设置为999,但您can change it if you need to

答案 1 :(得分:2)

您无法将数组绑定为IN (?)子句的列表。 IN列表中的每个值都必须获得其独特的占位符。

要使其动态化,首先确定值数组,然后动态构建SQL。

这将是您的代码:

$arrayParam = [10, 9, 6];
$placeHolders = implode(',', array_fill(0, count($arrayParam), '?'));
$sql = "SELECT * FROM table_name WHERE id IN ($placeHolders) AND name = ?";
// Merge the "array" parameter values with any other parameter values
// into one non-nested array:
$params = array_merge($arrayParam, ['myname']);
// ...
    foreach ($params as $index => $val) {
        // No sub arrays allowed:
        $ok = $stmt->bindValue($index + 1, $val, getArgType($val));
        // ... etc

答案 2 :(得分:2)

(警告:这个答案是在'mysql'标签被删除之前写的;我不知道addslashes是否适用于sqlite3。)

在PHP中,将$ list作为发往IN列表的值数组:

$list = array(1, 2, 'abcd', 'double quote: "', "apostrophe: don't");
$ins = implode(', ', array_map(
        function($a) {
               return "'" . addslashes($a) . "'";
                     }, $list));
echo $sql = "... IN ($ins) ...";;

产量

... IN ('1', '2', 'abcd', 'double quote: \"', 'apostrophe: don\'t') ...

(是的,这可以通过正常的for循环完成,而不使用array_map和“匿名函数”。)

别担心;对于数字列,数字('123')的引号是正常的。

答案 3 :(得分:2)

我建议你尝试做一些解决方法。将查询结果传递给临时表。

// a helper function to map Sqlite data type
function getArgType($arg) {
        switch (gettype($arg)) {
            case 'double':  return SQLITE3_FLOAT;
            case 'integer': return SQLITE3_INTEGER;
            case 'boolean': return SQLITE3_INTEGER;
            case 'NULL':    return SQLITE3_NULL;
            case 'string':  return SQLITE3_TEXT;
            default:
                throw new \InvalidArgumentException('Argument is of invalid type '.gettype($arg));
        }
}
function getTempValues() {
$sql = "SELECT * FROM `myTemp`";
$params = [$in]; // array of array
$dbpath = '/path/to/sqlite.sqlite';
$db = new SQLite3($dbPath, SQLITE3_OPEN_READONLY);
$stmt = $db->prepare($sql);
$result = $stmt->execute();
    $data = [];
    while ($row = $result->fetchArray($mode)) {
        $data[] = $row;
    }
    return $data;
}
function addToTemp($in) {
$sql = "SELECT * INTO `myTemp` FROM `table_name` WHERE `id` = ?";
$params = [$in]; // array of array
$dbpath = '/path/to/sqlite.sqlite';
$db = new SQLite3($dbPath, SQLITE3_OPEN_READONLY);
$stmt = $db->prepare($sql);
if(is_array($in)) {
foreach($in as $newValue) {
addToTemp($newValue);
}
} else {
 try {
        foreach ($params as $index => $val) {
                $ok = $stmt->bindValue($index + 1, $val, getArgType($val)); 
            if (!$ok) {
                throw new Exception("Unable to bind param: $val");
            }
        }
    } catch (Exception $ex) {
        // NO exception is thrown from bindValue() or bindParam()
        $reason = "Error in binding statement. " . $ex->getMessage();
        die($reason);
    }

    $stmt->execute();
}
 return getTempValues();
}

print_r(addToTemp([10,9,6]));

答案 4 :(得分:1)

你可以添加吗?占位符与数组中的项目数一样多

Select * from table_a where field in (?,?,?,?,?,?,?,.....)

如果它们大于1000,则将它们分成两个或多个查询。