PHP MySQL PDO: как сохранить ведущие нули столбцов zerofill int

Я ударил еще один удар по пути перехода от старых функций mysql_*() к новому классу PDO: У меня есть следующая таблица:

CREATE TABLE `test` (
  `Id` tinyint(4) unsigned zerofill NOT NULL,
  `UserName` varchar(4) NOT NULL,
  `TestDecimal` decimal(6,0) unsigned zerofill DEFAULT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Обратите внимание на поля с нулевым значением Id и TestDecimal.

Если я запустил следующий код, используя старые функции mysql_*():

$SqlQuery = "SELECT * FROM test";
$Sql_Result = mysql_query($SqlQuery);
var_dump(mysql_fetch_array($Sql_Result));

Я получаю следующий вывод с корректно нулевым столбцом Id:

array (size=6)
  0 => string '0001' (length=4)
  'Id' => string '0001' (length=4)
  1 => string 'alex' (length=4)
  'UserName' => string 'alex' (length=4)
  2 => string '000002' (length=6)
  'TestDecimal' => string '000002' (length=6)

Однако, если я делаю то же самое с использованием PDO, например:

$SqlQuery = "SELECT * FROM test";
$SqlResult = $MysqlPDO->prepare($SqlQuery);
$SqlResult->execute();
var_dump($SqlResult->fetch(PDO::FETCH_BOTH));

Я получаю этот вывод с некорректно отличным от нуля столбцом Id:

array (size=6)
  'Id' => int 1
  0 => int 1
  'UserName' => string 'alex' (length=4)
  1 => string 'alex' (length=4)
  'TestDecimal' => string '000002' (length=6)
  2 => string '000002' (length=6)

Кажется, что класс PDO смотрит на тип столбца и возвращает соответствующий тип переменной (целочисленный в этом случае) в PHP. После некоторого поиска я узнал об атрибуте PDO::ATTR_STRINGIFY_FETCHES, который можно настроить для принудительного возвращения всех результатов MYSQL в виде строк, в то время как это, похоже, работает (я получаю строку вместо int), она по-прежнему не возвращает ведущие нули:

array (size=6)
  'Id' => string '1' (length=1)
  0 => string '1' (length=1)
  'UserName' => string 'alex' (length=4)
  1 => string 'alex' (length=4)
  'TestDecimal' => string '000002' (length=6)
  2 => string '000002' (length=6)

Кажется, что он корректно работает с полем decimal(6,0) zerofill, но не с полем tinyint(4) zerofill... Есть ли способ сделать эту работу, или мне придется перебирать свою кодовую базу и выяснять, что ломается с этим изменением (я уже определил пару вещей, которые больше не работают...)?

Демо-код.

Ответы

Ответ 1

вы можете использовать LPAD?

попробуйте следующее: SELECT *, LPAD( Id, 3, '0') AS zero_Fill_Id FROM test

должен измениться 3 в соответствии с размером int: возможно, 4 для этой ситуации?

Update:

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

Я думаю, что вы используете драйвер mysqlnd, что я нашел об этом (проверьте, включен ли Как узнать, является ли MySQLnd активным драйвером?):

Преимущества использования mysqlnd для PDO

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

source: Как получить числовые типы из MySQL с помощью PDO?

В этом случае есть PDO::ATTR_STRINGIFY_FETCHES, который в вашем случае должен быть установлен в true, также вы можете попробовать попробовать PDO::ATTR_EMULATE_PREPARES атрибут далее: PDO MySQL: использовать PDO:: ATTR_EMULATE_PREPARES или нет?

...
$pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);

Надеюсь, это поможет в любом случае или в любом случае:))

Ответ 2

Если вы хотите исправить это, не изменяя код приложения, вы можете изменить определение столбца в своей базе данных на DECIMAL(9,0).

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

Ответ 3

Я бы написал небольшую процедуру для исправления вывода PDO в соответствии с требованиями и попытался сделать наименьшее количество изменений в кодировке.

$results = pdoFix($SqlResult->fetchAll(PDO::FETCH_BOTH))

function pdoFix($results) {
    foreach ($results as &$row) { // note the "&"
      $row[0] = sprintf("%'04s",$row[0]); // zerofill '0'
      $row['id'] = sprintf("%'04s",$row['id']); // zerofill 'id'
    }
    unset($row); // break the reference with the last element
    return $results;
}

Примечание. Другие ответы так же хороши, выберите тот, который вам наиболее удобен.