Як вставити значення NULL за допомогою PDO?


105

Я використовую цей код, і я переживаю розчарування:

try {
    $dbh = new PDO('mysql:dbname=' . DB . ';host=' . HOST, USER, PASS);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $dbh->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
}
catch(PDOException $e)
{
    ...
}
$stmt = $dbh->prepare('INSERT INTO table(v1, v2, ...) VALUES(:v1, :v2, ...)');
$stmt->bindParam(':v1', PDO::PARAM_NULL); // --> Here's the problem

PDO::PARAM_NULL, null, '', всі вони виходять з ладу і кидають цю помилку:

Фатальна помилка : Неможливо передати параметр 2 за посиланням у / opt / ...

Відповіді:


138

Я просто вивчаю PDO, але я думаю, що вам потрібно користуватися bindValue, а неbindParam

bindParamприймає змінну для посилання і не отримує значення під час виклику bindParam. Я виявив це в коментарі до документів php:

bindValue(':param', null, PDO::PARAM_INT);

EDIT: PS Ви можете зробити це спокусою, bindValue(':param', null, PDO::PARAM_NULL);але це не спрацювало для всіх (спасибі Вілл Шейвер за повідомлення).


Я не впевнений у різниці між цими двома, але я розслідую деякі. Спасибі, і ваша відповідь була чудовою.
Начо

3
Я думаю, що це може бути кращою відповіддю, ніж моя (якщо вона справді працює)
Джо Філіпс

2
У мене виникли проблеми з PDO :: PARAM_NULL на MySql 5.1.53, але PDO :: PARAM_INT з нульовим значенням спрацював чудово.
Буде Шавер

2
Одін: Я думаю, що найважливіша частина - це передати всі три параметри :). у запитанні ign він передавав PDO :: PARAM_NULL як значення, а не як тип (і зовсім не передає тип)
JasonWoof

1
FYI: у більшості випадків ви абсолютно добре використовуєте bindValue()більше bindParam(); для всього, а не лише для NULLвартості. Я не можу придумати жодного випадку, коли вам потрібно було б прив’язати параметр до посилання змінної PHP - але це bindParam()робиться.
low_rents

48

При використанні bindParam()ви повинні передавати змінну, а не константу. Тому перед цим рядком потрібно створити змінну та встановити їїnull

$myNull = null;
$stmt->bindParam(':v1', $myNull, PDO::PARAM_NULL);

Ви отримаєте те саме повідомлення про помилку, якби ви спробували:

$stmt->bindParam(':v1', 5, PDO::PARAM_NULL);

Ви зрозуміли це право, я щойно зрозумів, що раніше це робив у своєму коді, $ null = PDO :: PARAM_NULL; Дякую.
Начо

1
У цьому випадку краще використовувати bindValue (), якщо ви все-таки будете робити заповнювачі. bindParam () спочатку призначений для виконання запиту, а потім зміни змінних та повторного виконання, не прив'язуючи параметри знову. bindValue () прив'язується негайно, bindParam () лише під час виконання.
Хьюго Цинк

1
Я виявив, що в рядку $ myNull = null null має бути малі літери. $ myNull = NULL НЕ працює.
raphael75

28

При використанні INTEGERстовпців (це може бутиNULL ) у MySQL, PDO має деяку (для мене) несподівану поведінку.

Якщо ви користуєтесь $stmt->execute(Array), вам слід вказати буквальне значення NULLі не можна наводити NULLзмінну посилання. Отже, це не спрацює:

// $val is sometimes null, but sometimes an integer
$stmt->execute(array(
    ':param' => $val
));
// will cause the error 'incorrect integer value' when $val == null

Але це спрацює:

// $val again is sometimes null, but sometimes an integer
$stmt->execute(array(
    ':param' => isset($val) ? $val : null
));
// no errors, inserts NULL when $val == null, inserts the integer otherwise

Спробував це на MySQL 5.5.15 за допомогою PHP 5.4.1


1
$ stmt-> Execute (array (': param' =>! порожній ($ val)? $ val: null)); Використовуйте! Empty, тому що для порожнього рядка ви також хочете встановити null у базі даних
Shehzad Nizamani

1
@ShehzadNizamani Тільки якщо тип стовпця цілий, як у його прикладі, так. Але в іншому випадку isset()корелює краще NULL. Порожній рядок - також значення.
СТЕН

8

Для тих, хто все ще має проблеми (Неможливо передати параметр 2 за посиланням), визначте змінну з нульовим значенням, а не просто передайте null PDO:

bindValue(':param', $n = null, PDO::PARAM_INT);

Сподіваюся, це допомагає.


6

У мене була така ж проблема, і я знайшов це рішення, працюючи з bindParam:

    bindParam(':param', $myvar = NULL, PDO::PARAM_INT);

3

Якщо ви хочете вставити NULLтільки тоді , коли valueє emptyабо '', але вставитиvalue , коли вона доступна.

A) Отримує дані форми за допомогою методу POST і функцію викликів вставляє з цими значеннями.

insert( $_POST['productId'], // Will be set to NULL if empty    
        $_POST['productName'] ); // Will be to NULL if empty                                

B) Оцінює, якщо користувач не заповнив поле, і вставляє, NULLякщо це так.

public function insert( $productId, $productName )
{ 
    $sql = "INSERT INTO products (  productId, productName ) 
                VALUES ( :productId, :productName )";

    //IMPORTANT: Repace $db with your PDO instance
    $query = $db->prepare($sql); 

    //Works with INT, FLOAT, ETC.
    $query->bindValue(':productId',  !empty($productId)   ? $productId   : NULL, PDO::PARAM_INT); 

    //Works with strings.
    $query->bindValue(':productName',!empty($productName) ? $productName : NULL, PDO::PARAM_STR);   

    $query->execute();      
}

Наприклад, якщо користувач нічого не вводить у productNameполе форми, $productNameбуде, SETале EMPTY. Отже, вам потрібно перевірити, чи є empty(), а якщо є, то вставити NULL.

Тестовано на PHP 5.5.17

Удачі,


3
Або ви можете використовувати IFNULL()функцію MySQL у рядку запиту. $sql = "INSERT INTO products ( productId, productName ), VALUES ( IFNULL(:productId, NULL), IFNULL(:productName, NULL) )";
Ось так

Мені подобається чистота вашого рішення. Я просто перевірив це, але, на жаль, він вставляє порожні рядки замість NULL, коли користувач нічого не пише на вхід. Це просто питання уподобань, але я швидше маю NULL замість порожніх рядків.
Аріан Акоста

0

Спробуйте це.

$stmt->bindValue(':v1', null, PDO::PARAM_NULL); // --> insert null

1
Перш ніж спробувати відповісти на таке давнє запитання, слід спочатку прочитати інші відповіді. Можливо, на нього вже відповіли.
Твій здоровий глузд

0

На основі інших відповідей, але з трохи більшою чіткістю щодо того, як насправді використовувати це рішення.

Якщо, наприклад, у вас є порожня рядок для значення часу, але ви хочете зберегти її як нуль:

  if($endtime == ""){
    $db->bind(":endtime",$endtime=NULL,PDO::PARAM_STR);
  }else{
    $db->bind("endtime",$endtime);
  }

Зауважте, що для часових значень ви б використовували PARAM_STR, оскільки рази зберігаються як рядки.


-1

У моєму випадку я використовую:

  • SQLite,

  • підготовлені заяви із заповнювачами для обробки невідомої кількості полів,

  • Запит AJAX, надісланий користувачем, де все є рядком, і немає такого поняття, як NULLvalue and

  • Мені відчайдушно потрібно вставити NULLs, оскільки це не порушує обмежень іноземних ключів (прийнятне значення).

Припустимо, тепер користувач відправляє з пост: $_POST[field1]зі значенням , value1яке може бути символом нового рядка ""або "null"або "NULL".

Спочатку роблю заяву:

$stmt = $this->dbh->prepare("INSERT INTO $table ({$sColumns}) VALUES ({$sValues})");

де що- {$sColumns}небудь схоже field1, field2, ...і {$sValues}є моїми заповнювачами ?, ?, ....

Потім я збираю свої $_POSTдані, пов’язані з іменами стовпців у масиві, $values і замінюю на NULLs:

  for($i = 0; $i < \count($values); $i++)
     if((\strtolower($values[$i]) == 'null') || ($values[$i] == ''))
        $values[$i] = null;

Тепер я можу виконати:

$stmt->execute($values);

і серед інших обхідних зовнішніх ключових обмежень.

Якщо, з іншого боку, порожній рядок має більше сенсу, то вам доведеться перевірити, чи є це поле частиною іноземного ключа чи ні (складніше).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.