Ціле поле MySQL повертається як рядок у PHP


127

Я маю поле таблиці в базі даних MySQL:

userid INT(11)

Тому я закликаю його на свою сторінку із цим запитом:

"SELECT userid FROM DB WHERE name='john'"

Тоді для обробки результату я роблю:

$row=$result->fetch_assoc();

$id=$row['userid'];

Тепер, якщо я:

echo gettype($id);

Я отримую рядок. Чи не повинно це бути цілим числом?


2
запит MySQL дає значення рядків, а не типи рядків або будь-яку іншу пов’язану інформацію. Тільки необроблені дані, які є в кожній комірці таблиці. Вам доведеться пояснити це в PHP
Dan Hanly

Якщо вам потрібні типи стовпців, дивіться тут forums.whirlpool.net.au/archive/526795
RichardTheKiwi

Для читачів обрана відповідь передбачає повторення результатів. Але є краще рішення. stackoverflow.com/a/1197424/5079380
Амр ElAdawy

1
@DanHanly - технічно запит MYSQL (у PHP) повертає рядкове подання значення комірки - фактичне значення комірки, що зберігається в базі даних для 32-бітного цілого числа, це ... 32-бітове ціле число, а не рядок цифр .
ToolmakerSteve

для мене, коли я використовував, $conn->query("your query")я отримав цілі поля як рядок, але коли я використав, $conn->prepare("your query")я отримав параметри, як вони були в базі даних
Bar Tzadok

Відповіді:


129

Коли ви вибираєте дані з бази даних MySQL за допомогою PHP, тип даних завжди буде перетворений у рядок. Ви можете перетворити його назад у ціле число, використовуючи наступний код:

$id = (int) $row['userid'];

Або за допомогою функції intval():

$id = intval($row['userid']);

79
Прийшовши до MySQL з фоном Postgres, я відчуваю потребу сказати, що це величезний біль у попці. Коли ви отримували рядок у Postgres, ви можете бути впевнені, що елементи в масиві рядків мали відповідні типи даних. Тепер мені доводиться писати код, щоб вручну передати кожен елемент тому типу даних, який я очікую.
GordonM

25
Я щойно робив кілька тестів на Windows з Laravel та Mysql на тій же схемі та сервері баз даних. У Windows первинний ключ повертається як Integer, а в Linux - String.
AturSams

Гаразд, це гарна ідея, але що робити, якщо у вас є тисячі полів для отримання? Цей процес потребує певного часу. У моєму прикладі я отримую кількість переглядів для кожної публікації, потім друкую всю свою публікацію в таблиці, я дозволяю користувачеві сортувати за переглядом у вхідному і дескрипційному порядку, але це сортування за "1" до "9 "або" 9 "до" 1 ", тож на першому місці у вас могли бути" 9999 "," 91 "," 8111 "," 7 "і т. д. ...
KeizerBridge

@zehelvion Ви коли-небудь знаходили рішення для цього?
Феліпе Франсіско

2
Кожне повернене поле буде рядком АБО NULL .
Ліам

73

Використовуйте mysqlnd (рідний драйвер) для php.

Якщо ви перебуваєте на Ubuntu:

sudo apt-get install php5-mysqlnd
sudo service apache2 restart

Якщо ви перебуваєте у Centos:

sudo yum install php-mysqlnd
sudo service httpd restart

Народний драйвер належним чином повертає цілі типи.

Редагувати:

Як зазначав @Jeroen, цей метод буде працювати тільки в PDO для PDO.
Як зазначав @LarsMoelleken, цей метод буде працювати з mysqli, якщо ви також встановите для параметра MYSQLI_OPT_INT_AND_FLOAT_NATIVE значення true.

Приклад:

$mysqli = mysqli_init();
$mysqli->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, TRUE);

Я не бачу доказів цього твердження. Запуск з mysqlnd та mysqli повертаються чітко рядкові значення.
Йероен

@Jeroen Ви впевнені? Є багато документації. stackoverflow.com/questions/1197005 / ...
advait

так. Також дивіться коментарі нижче. Ви самі це перевіряли? як виглядає зараз, навіть mysqlnd повертає відповідні типи лише у тому випадку, якщо ви використовуєте підготовлені оператори. приклад: $link = mysqli_connect('localhost', 'root', ''); mysqli_set_charset($link,'utf8'); $result = mysqli_query($link,'SELECT CAST(\'3.51\' AS DECIMAL(3,2))'); $row = mysqli_fetch_assoc($result); var_dump($row);повертає: array(1) { ["CAST('3.51' AS DECIMAL(3,2))"]=> string(4) "3.51" }
Jeroen

1
Не як я це розумію, він повинен однаково співпрацювати з PDO та Mysqli. Навіть на посиланні, яке ви розміщуєте вище у коментарі, чітко зазначено, що він працює ТІЛЬКО З ПІДГОТОВКИМИ ВІДОМОСТАМИ, а не вбудованими запитами згідно з ОП. цитата з цієї сторінки: Але це лише PHP 5.3 (за умови, що ваша версія PHP 5.3 зібрана з mysqlnd (а не старий libmysql)), і, здається, це стосується лише підготовлених заяв :-(
Jeroen

7
ви також можете використовувати "MYSQLI_OPT_INT_AND_FLOAT_NATIVE" для mysqli
Lars Moelleken

20

Найпростіше рішення, яке я знайшов:

Ви можете змусити json_encode використовувати фактичні числа для значень, схожих на числа:

json_encode($data, JSON_NUMERIC_CHECK) 

(оскільки PHP 5.3.3).

Або ви можете просто віддати свій ідентифікатор до int.

$row = $result->fetch_assoc();
$id = (int) $row['userid'];

1
Використання json_encodeв гіпс рядки в цілому , якщо це можливо, як з допомогою мікроскопа задихатися нігтями.
LibertyPaul

7
Це порушить усі поштові індекси та номер телефону. Хороший спосіб представити помилки у вашому додатку. Рішення ОБОВ'ЯЗКОВО поважати тип даних стовпця mysql, а не намагатися вгадати зі значення.
Макс Куттінс

1
Макс Кеттінс, ваша точка дійсна. Однак, якщо ви можете врахувати всі типи даних, які очікуються від БД, то це був би ідеальний шлях.
Іфєді Оконкво

1
Це зашкодить вам, коли у вас колись з'являться подібні ідентифікатори типу "06". Цей прапор перетворить його на 6. Що неправильно, оскільки ці ідентифікатори повинні зберігати нулі.
Хассан тато Хан

Це чудове рішення для значень, створених UNIX_TIMESTAMP(), наприклад.
Девід

18

Моє рішення полягає в тому, щоб передати результат запиту $rsі отримати масив асоційованих даних закинутих даних як повернення:

function cast_query_results($rs) {
    $fields = mysqli_fetch_fields($rs);
    $data = array();
    $types = array();
    foreach($fields as $field) {
        switch($field->type) {
            case 3:
                $types[$field->name] = 'int';
                break;
            case 4:
                $types[$field->name] = 'float';
                break;
            default:
                $types[$field->name] = 'string';
                break;
        }
    }
    while($row=mysqli_fetch_assoc($rs)) array_push($data,$row);
    for($i=0;$i<count($data);$i++) {
        foreach($types as $name => $type) {
            settype($data[$i][$name], $type);
        }
    }
    return $data;
}

Приклад використання:

$dbconn = mysqli_connect('localhost','user','passwd','tablename');
$rs = mysqli_query($dbconn, "SELECT * FROM Matches");
$matches = cast_query_results($rs);
// $matches is now a assoc array of rows properly casted to ints/floats/strings

2
Прекрасним рішенням, крім 'NULL', є також тип змінної, який використовується функцією stalype (). Таким чином ваш код змінює всі значення NULL, повернені базою даних (значення, де gettype () == 'NULL'), на тип 'string' зі значенням '', 'integer' з 0 значенням або типу 'float' з значенням 0,0. Вам не потрібно зателефонувати у адресному значенні, якщо is_null ($ data [$ i] [$ name]) вірно.
Зимова драконя

Мені подобається техніка натхнення, але кодування може бути простішим .
ToolmakerSteve

13

Ні. Незалежно від типу даних, визначеного у ваших таблицях, драйвер MySQL PHP завжди подає значення рядків як рядки.

Потрібно віддати свій ідентифікатор до int.

$row = $result->fetch_assoc();
$id = (int) $row['userid'];

6
За цю поведінку (безпосередньо) не відповідає PHP, це драйвер бази даних. Якщо ви з'єднуєтесь із базою даних Postgres з PHP, ви отримаєте відповідні типи даних.
GordonM

5

Мені подобається відповідь Чада, особливо коли результати запиту будуть передані на javascript у браузері. Javascript справляється з числовими сутностями як числами, але вимагає додаткової роботи для роботи з числовими сутностями як рядками. тобто потрібно використовувати parseInt або parseFloat на них.

Спираючись на рішення Чада, я використовую це, і це часто саме те, що мені потрібно, і створює структури, які можуть бути закодовані JSON для легкого спілкування з JavaScript.

while ($row = $result->fetch_assoc()) {
    // convert numeric looking things to numbers for javascript
    foreach ($row as &$val) {
        if (is_numeric($val))
            $val = $val + 0;
    }
}

Додавання числового рядка до 0 створює числовий тип у PHP і правильно ідентифікує тип, так що числа з плаваючою комою не будуть усічені в цілі числа.


5

Це відбувається, коли PDO::ATTR_EMULATE_PREPARESдля trueз'єднання встановлено значення.

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


2

Це можна зробити за допомогою ...

  1. mysql_fetch_field ()
  2. mysqli_result :: fetch_field_direct або
  3. PDOStatement :: getColumnMeta ()

... залежно від розширення, яке ви хочете використовувати. Перший не рекомендується, оскільки розширення mysql застаріле. Третя ще експериментальна.

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

Деякі рамки також абстрагують це (надає CodeIgniter $this->db->field_data()).

Ви також можете зробити здогадки - наприклад, перебираючи свої рядки та використовуючи is_numeric () для кожного. Щось на зразок:

foreach($result as &$row){
 foreach($row as &$value){
  if(is_numeric($value)){
   $value = (int) $value;
  }       
 }       
}

Це перетворило б все, що виглядає як число, в одне ... точно не ідеальне.


Не працює для поплавків. Вони проходять тест is_numeric. Спершу слід перевірити на поплавці.
Мартін ван Дріел

@MartinvanDriel або будь-який рядок, який містить лише числа, але має бути рядок
дерево дерева

@MartinvanDriel Спробуйте додати:if (is_float()) { $value = (float)$value; }
adjwilli

2

У своєму проекті я зазвичай використовую зовнішню функцію, яка "фільтрує" дані, отримані за допомогою mysql_fetch_assoc.

Ви можете перейменувати поля в таблиці, щоб зрозуміти, який тип даних зберігається.

Наприклад, ви можете додати спеціальний суфікс до кожного числового поля: якщо useridце INT(11)ви, то можете перейменувати його userid_iабо якщо він є, UNSIGNED INT(11)ви можете перейменувати userid_u. У цей момент ви можете написати просту функцію PHP, яка отримує як вхідний асоціативний масив (отриманий з mysql_fetch_assoc), і застосовує кастинг до "значення", що зберігається за допомогою цих спеціальних "клавіш".


1

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

function dbQuery($sql) {
    global $mysqli;

    $stmt = $mysqli->prepare($sql);
    $stmt->execute();
    $stmt->store_result();

    $meta = $stmt->result_metadata();
    $params = array();
    $row = array();

    while ($field = $meta->fetch_field()) {
      $params[] = &$row[$field->name];
    }

    call_user_func_array(array($stmt, 'bind_result'), $params);

    while ($stmt->fetch()) {
      $tmp = array();
      foreach ($row as $key => $val) {
        $tmp[$key] = $val;
      }
      $ret[] = $tmp;
    }

    $meta->free();
    $stmt->close();

    return $ret;
}

1

У MySQL є драйвери для багатьох інших мов, які перетворюють дані в рядки "стандартизують" дані та залишають їх користувачеві для введення значень для передачі в int чи інші


1
Я вважаю, примітивні типи - це майже "стандарт"? Якщо водій, що відповідає мові, не зміг би задовольнити потреби в цій мові, я б сказав, що це дуже невтішно
Chung

1

У моєму випадку mysqlnd.soбуло встановлено розширення. Але я не був pdo_mysqlnd.so. Отже, проблему було вирішено заміною pdo_mysql.soна pdo_mysqlnd.so.


0

Мені подобається техніка натхнення , але кодування може бути простішим:

function cast_query_results($result): array
{
    if ($result === false)
      return null;

    $data = array();
    $fields = $result->fetch_fields();
    while ($row = $result->fetch_assoc()) {
      foreach ($fields as $field) {
        $fieldName = $field->name;
        $fieldValue = $row[$fieldName];
        if (!is_null($fieldValue))
            switch ($field->type) {
              case 3:
                $row[$fieldName] = (int)$fieldValue;
                break;
              case 4:
                $row[$fieldName] = (float)$fieldValue;
                break;
              // Add other type conversions as desired.
              // Strings are already strings, so don't need to be touched.
            }
      }
      array_push($data, $row);
    }

    return $data;
}

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


Я не заважаю використовувати це в більшості php-коду; Я просто покладаюся на автоматичне перетворення типу php. Але якщо запитувати багато даних, щоб потім виконати арифметичні обчислення, доцільно перейти до оптимальних типів вперед.

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