Null из PHP в SQL запрос - за и против.

WMix

герр M:)ller
Партнер клуба
Хот одну ситуацию подобную приведи, когда это нужно.
Всегда когда нужно отличать пусто от NULL
думаем в первую очередь про операторы
concat( 'a', NULL ), SUM( NULL ), 1+NULL, 'mama'<NULL

как пример concat( улица, дом, корпус, подьезд, этаж, задний_проход)

в этих полях лучше пусто, когда нет задний_проход и NULL когда еще не введен
 

MiksIr

miksir@home:~$
то есть у чекбокса либо true либо null
доооооооооо
Да, увы. Решается 2-я способами - или же у нас это поле NOT NULL DEFAULT 0, что есть нормально, ибо поле NULL должно быть только тогда, когда семантически нам этот NULL нужен в этом поле и он отличен от пустой строки или нуля.
Второй способ - hidden поле с тем же именем и value="0"
Хот одну ситуацию подобную приведи, когда это нужно.
В ссылке на mysql.com в самом верху приведен такой пример.
Это с точки зрения PHP есть значение. А с точки зрения пользователя - нет. И пустое поле об этом говорит - у меня нет значения. Не заполнен URL адрес в форме, значит у пользователя его НЕТ, нет значения. А вы пишите в базу пустую сроку как значение. Зачем хранить абсолютно ложную информацию? Пустое значение не может быть URL адресом.
А причем тут пользователь? Вы проектируете структуру данных и взаимодействие вашего кода с базой, а не то, как и что увидит в результате пользователь. Забейте, не нужен вам NULL - не используйте. Но не делайте такой лажи, как вы привели - делайте просто NOT NULL поле.
 

Фанат

oncle terrible
Команда форума
А если вернуться к исходному вопросу - подстановке переменно с заранее неизвестным значением в запрос.
Вроде бы, пришли к выводу, что в селектах такая ситуация невозможна. Значит - только инсерты?
И вот для инсерта мы должны решить - делать из пхпшного нулла мускулевский нулл, или оставлять как есть (позволив пхпе превратить его в пустую строку или ноль, в зависимости от типа передаваемых данных).
 

AmdY

Пью пиво
Команда форума
Фанат
а почему это класс должен решать, а не сам разработчик указывать? у тебя же свои плейсхолдеры, почему бы не задавать поведение через них.
field = ?stringOrNull
field = ?intOrNull
 

Фанат

oncle terrible
Команда форума
Это крайняя мера, и я бы хотел её избежать, при возможности.
Вот как раз из-за нежелания вводить отдельный плейсхолдер (или даже класс плейсхолдеров) я, собственно, и задал этот вопрос.
Просто до сих пор передо мной такой вопрос не вставал ни разу. Именно на практике. Но вот спрашивают его.
 

Василий М.

Новичок
А причем тут пользователь? Вы проектируете структуру данных и взаимодействие вашего кода с базой, а не то, как и что увидит в результате пользователь. Забейте, не нужен вам NULL - не используйте. Но не делайте такой лажи, как вы привели - делайте просто NOT NULL поле.
не при чем. с точки зрения здравого смысла - если пользователь что-то не указал, значит знаний у нас об этом нет. это NULL.
то, что "от пользователя" приходит пустая строка - это издержки платформы.

ситуация с чекбоксами - аналогична. нужно нам ноль иметь в БД - пишем hidden поле, нет - значит и нет записи.
 

Beavis

Banned
Это крайняя мера, и я бы хотел её избежать, при возможности.
Вот как раз из-за нежелания вводить отдельный плейсхолдер (или даже класс плейсхолдеров) я, собственно, и задал этот вопрос.
Просто до сих пор передо мной такой вопрос не вставал ни разу. Именно на практике. Но вот спрашивают его.
в dbsimple мне кажется удобно реализовано (плейсхолдер ?n)
 

MiksIr

miksir@home:~$
Зайдем с другой стороны. Раз вы поле varchar объявили как NULL, значит при проектировании базы вы заранее обозначили, что ваше поле должно находится в 3-х состояниях: есть текст, нет текста (пустая строка), NULL. И все три состояния должны быть использованы, ибо зачем тогда их три? Пустой ввод от пользователя вы отпределяете как NULL. Вопрос - на какое событие вы зарезервировали состояние "пустая строка"?
 

Фанат

oncle terrible
Команда форума
Как-то мне этот плейсхолдер кажется неюзабельным. Интересно посмотреть его в деле, а не в примере.
 

MiksIr

miksir@home:~$
А в чем смысл плейсходера ?n
Я понимаю ?intOrNull, но просто ?n

А вообще исходить нужно из целей. У нас цель защитить новичков с отключенным стриктом подать неопределенную переменную? Тогда php-шный null использовать нельзя и никакие плейсхолдеры не помогут. Если ориентируемся на уровень выше, который никогда не будет без стрикта работать - можно null использовать, об ошибке сообщит PHP.
 

WMix

герр M:)ller
Партнер клуба
Василий М.
не при чем. с точки зрения здравого смысла - если пользователь что-то не указал, значит знаний у нас об этом нет. это NULL.
я полностью с тобою согласен, значения нет, но зато есть информация что пользователь видел этот вопрос, ...
записывать эту дополнительную инфу или нет, вопрос исключительно концепта...

если есть желание клиента записывать или значение или NULL то возможно можно автоматом превратить null в NULL (нужно думать)...
важно всеже понимать, что постоянно так делать не правильно,
 

Фанат

oncle terrible
Команда форума
А в чем смысл плейсходера ?n
Я понимаю ?intOrNull, но просто ?n
Я так понял, что ?n - это неявный ?StrOrNull.
? без ничего - это строковый плейсхолдер, а с n - соответственно, строка или нулл

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

~WR~

Новичок
Глубоко убежден, что класс для работы с БД не должен содержать никакой хитрой логики.
В каком формате он возвращает данные из базы, в таком же и должен записывать их обратно.

Логично ожидать, что следующая операция всегда приведет к вставке точно такого же ряда, который был выбран.
PHP:
$row = $DB->selectRow("SELECT * FROM table WHERE ...");
$DB->insert('table', $row);
Если это не так, то вы роете яму сами себе и другим разработчикам.

Пустая строка это пустая строка. Null это null. Между ними - пропасть.
Если по логике приложения нужно записывать null вместо пустых строк, то это должно решаться не на уровне query builder'а, а на уровне той сущности, которая передает в него параметры.
 

Фанат

oncle terrible
Команда форума
~WR~
так NULL, как раз, и возвращается в виде пустой строки! %)

а если серьёзно - можешь привести пример содержимого этого $row? чтобы NULL записывал?
 

~WR~

Новичок
Эээ, с каких пор? Сколько живу, всегда *_fetch_(row|assoc) возвращали Null в базе как php Null.
Если в каких-то случаях это может быть не так (кажется, слышал про Oracle), то это шляпа полная...

Пример:
PHP:
$row = array(
    'name' => 'Test',
    'product' => null,
    'start_date' => '2012-01-01 00:00:00',
    'end_date' => null,
);

$DB->insert('table', $row);
PHP:
INSERT INTO table (name, product, start_date, end_date)
VALUES ('Test', null, '2012-01-01 00:00:00', null)
 

~WR~

Новичок
На мой взгляд, наилучшая политика в плане работы с БД - это сделать максимально простые обертки для самых тривиальных запросов.
Простой INSERT одного ряда, простой UPDATE ... SET ... WHERE a=1 [ AND b=2] и т.п.
Это отлично подходит для 90% случаев.

Если нужно что-то более хитрое, то лучше вручную написать plain sql с плейсхолдерами.
Это будет понятнее и вам, и тем, кто потом попытается разобраться в вашем коде.

SQL слишком многообразен, чтобы его можно было полностью покрыть builder'ами и не превратить код в монстра. Чем всё проще работает, тем лучше.

Кстати, сам на собеседованиях видел людей, которые не знают о том, что в update в некоторых случаях можно эффективно сделать sub-select. Просто они привыкли работать с #имя_фреймворка#, который это не позволяет.
 

WMix

герр M:)ller
Партнер клуба
Эээ, с каких пор? Сколько живу, всегда *_fetch_(row|assoc) возвращали Null в базе как php Null.
я был поражен у меня тоже....

PHP:
CREATE TABLE IF NOT EXISTS `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(5) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

class Test extends Zend_Db_Table_Abstract{
    protected $_name = 'test';
}

$testModel = new Test();
$testModel->insert( array ('id' => null, 'name' => null) );
Код:
mysql> SELECT *
    -> FROM `test`
    -> LIMIT 0 , 30;
+----+------+
| id | name |
+----+------+
|  1 | NULL |
+----+------+
PHP:
var_dump($this->getAdapter()->fetchAll(
	$this->select()->from($this->_name, '*')
));
Код:
array(1) {
  [0]=>
  array(2) {
    ["id"]=>
    string(1) "1"
    ["name"]=>
    NULL
  }
}
 

~WR~

Новичок
Если речь о том, что в авто-инкремент вставляется id вместо null, то это костыль mysql.

В нормальной СУБД, если пользователь явно пытается записать null, значит он именно этого и хочет. И надо показать ему ошибку, что поле NOT NULL.
А авто-инкремент должен вставляться либо тогда, когда поле опущено, либо когда явно указано значение DEFAULT. Логично же!

В mysql до фига таких приколов. Например, при попытке записать в поле tinyint число 300, он реально сохранит 255. Насрать ему на ваши данные.
Да, есть strict mode, есть варнинги. Но за всю жизнь я почти нигде не видел, чтобы это реально использовалось.
 

WMix

герр M:)ller
Партнер клуба
меня больше удивило запись null в поле имя, я ожидал ошибку...
по дикой наивности, я либо пропускал поле ожидая записи по default либо явно указывал через Zend_Db_Expr('NULL')
 

Фанат

oncle terrible
Команда форума
Ладно, уговорили.
Неочевидности плодить не буду.
Если программист хочет траслировать пхпшный нулл в мускулевский, то
PHP:
if ($insert['var'] === NULL) {
    unset($insert['var']);
}
$db->query("INSERT INTO table SET %u",$insert);
еще какие-нибудь реал-лайф кейсы будут?
 
Сверху