PDO Генерация заполнителей для привязки из массива и одного значения для нескольких операторов INSERT - PullRequest
2 голосов
/ 23 января 2020

Я пытаюсь сгенерировать один оператор вставки, который будет вставлять несколько строк. У меня есть и массив значений, который я хочу вставить в таблицу, в которой все используют один и тот же userkey.

. Я попытался использовать именованный параметр PDO и привязаться к нему, а затем передать в ролевый массив во время выполнения, но это не работает. Поэтому я перешел к заполнителям, но я не могу заставить это работать.

Я называю свою функцию как addUsersRoles(1, [100,101,102]);

И, глядя на сгенерированный SQL, я получаю:

INSERT user_roles (userkey, roleid) VALUES (?,?),(?,?),(?,?)

Я считаю правильным формат для вставки нескольких записей.

Исходя из этого, я пытаюсь сгенерировать:

INSERT user_roles (userkey, roleid) VALUES (1,100),(1,101),(1,102)

Как можно таким образом объединить силу привязки PDO к оператору SQL?

public function addUsersRoles($userkey, $roles = []){

        $in = str_repeat('?,', count($roles) - 1) . '?';

        $base_user_sql = 'INSERT user_roles (userkey, roleid) VALUES ';

        $sql = $base_user_sql;

        foreach ($roles as $role) {
            //$sql .= "(:USERKEY, $in),"; // Didn't Work
            $sql .= "($in),";
        }
        //Remove trailing comma
        $sql = rtrim($sql, ',');

        $db   = static::getDB();

        $stmt = $db->prepare($sql);
        //$stmt->bindValue(':USERKEY', $userkey, PDO::PARAM_STR);
        return $stmt->execute($roles);
    }

Ответы [ 3 ]

2 голосов
/ 23 января 2020

Вы также можете использовать заполнители. Посмотрите на следующий пример:

public function addUsersRoles(string $userKey, array $roles = []): bool 
{
    $values = [];
    $inputParameters = [':user_key' => $userKey];

    foreach ($roles as $index => $role) {
        $rolePlaceholder = ':roleid' . $index;
        $values[] = sprintf('(:user_key, %s)', $rolePlaceholder);
        $inputParameters[$rolePlaceholder] = $role; 
    }

    $sql = 'INSERT INTO user_roles (user_key, roleid) VALUES ';
    $sql .= implode(', ', $values);

    $db = static::getDB();

    $stmt = $db->prepare($sql);
    return $stmt->execute($inputParameters);
}

Этот код сгенерирует запрос следующим образом:

INSERT INTO user_roles (user_key, roleid) VALUES (:user_key, :roleid0), (:user_key, :roleid1), (:user_key, :roleid2), (:user_key, :roleid3), (:user_key, :roleid4);

И $ inputParameters будет выглядеть так:

[
    ':user_key' => 'some user key',
    ':roleid0' => 1,
    ':roleid1' => 2,
]
1 голос
/ 23 января 2020

Вы не должны использовать count($roles) при создании $in. Это всегда просто ?, ?. Вам просто нужно количество ролей при повторении этого для всех строк. Вы можете использовать array_fill для создания массива (?, ?) строк, а затем implode для ввода запятых между ними.

Вам также нужно вставить массив для создания альтернативных ключей и ролей и использовать его в качестве параметров при выполнении.

public function addUsersRoles($userkey, $roles = []){

    $values = implode(',', array_fill(0, count($roles), '(?, ?)'));
    $base_user_sql = 'INSERT user_roles (userkey, roleid) VALUES ';
    $sql = $base_user_sql . $values;

    $keys_and_roles = [];
    foreach ($roles as $role) {
        $keys_and_roles[] = $userkey;
        $keys_and_roles[] = $role;
    }

    $db   = static::getDB();

    $stmt = $db->prepare($sql);
    return $stmt->execute($keys_and_roles);
}
0 голосов
/ 23 января 2020

Я немного упростил это, но это делится на две части, которые делаются вместе. Первый - создать SQL ...

INSERT user_roles (userkey, roleid) VALUES (?,?),(?,?),(?,?)

. Этот код просто циклически перебирает роли и добавляет (?,?), для каждого.

Вторая часть создает связать данные. Поскольку SQL требуется список данных в ключе user user, roleid пар, поскольку он строит SQL, он также добавляет эти значения в массив данных одновременно.

Таким образом, основной код выглядит как ...

public function addUsersRoles($userkey, $roles = []){
    $sql = 'INSERT user_roles (userkey, roleid) VALUES ';
    $binds = [];
    foreach ( $roles as $role ) {
        $sql .=  "(?,?),";
        $binds[] = $userkey;
        $binds[] = $role;
    }
    //Remove trailing comma
    $sql = rtrim($sql, ',');
    $db   = static::getDB();

    $stmt = $db->prepare($sql);
    return $stmt->execute($binds)
}

(хотя я не смог протестировать исполняемую часть).

Вы также должны сделать уверен, что с любыми ошибками также разбираются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...