Бит выбора MySQL(1) отображается в виде строки(3)


У меня есть таблица со столбцом bit(1) и следующий запрос: SELECT my_bit FROM my_table.

Когда я echo получаю результат на странице php, значение отображается как string(3) %qu независимо от того, является ли значение бита в столбце 0 или 1. Как это возможно?

Следующий запрос решил проблему, когда echoing на веб-странице: SELECT CAST(my_bit AS UNSIGNED) AS my_bit FROM my_table.

Однако оба приведенных выше запроса работают с инструментом командной строки. Нет string(3) там.

Также все работает при выборе данных, нет разница между

  1. ВЫБЕРИТЕ *ИЗ my_table, ГДЕ my_bit=0
  2. ВЫБЕРИТЕ *ИЗ таблицы my_table, ГДЕ my_bit=(0)

При использовании инструмента командной строки или веб-интерфейса php страниц. (Последнее предлагается здесь.) Echoing должно быть сделано с помощью функции CAST, но на WHERE не влияет родительское значение: возвращаются правильные строки.

Основные вопросы

  1. Как получилось, что возвращаемое значение типа bit равно echoed как идентичное string независимо от того, значение bit равно 0 или 1?
  2. Существуют ли какие-либо особые проблемы, которые следует учитывать при вставке/выборе данных с использованием столбца типа bit(1)? (Быстрое тестирование показывает, что все работает так, как задумано: 0 вставляется как 0, а 1 как 1, но я могу что-то упустить.)

Я тестирую это локально с помощью MAMP: PHP 5.3.2 и MySQL 5.1.44. Инструмент командной строки относится к Sequel Pro (а не к PhpAdmin MAMP). Php страницы utf-8 и запросы используют SET NAMES 'utf8'.


Обновление: код

CREATE TABLE `my_table` (
  `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
  `my_bit` bit(1) NOT NULL,
  PRIMARY KEY (`id`,`lto_muu`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci;

INSERT INTO `my_table` (`id`, `my_bit`) VALUES (null, 0), (null,1)

//php page
//query option 1
SELECT `id`, `my_bit`  FROM `my_table`
//query option 2
SELECT `id`, CAST(`my_bit` AS UNSIGNED) AS `my_bit`  FROM `my_table`

$mysqli = new mysqli("localhost", "root", "root","my_db");
$q = "SELECT `id`, `my_bit`  FROM `my_table`";//returns 2 rows

$r = $mysqli->query($q);

while($row = mysqli_fetch_array($r,MYSQLI_ASSOC)){
echo 'id: ' . $row['id'] . ' - bit: ' . $row['my_bit'] . '<br />';
}

Вариант запроса 1 выводит:

id: 1 - bit: %qu
id: 2 - bit: %qu

Вариант запроса 2 выводит:

id: 1 - bit: 0
id: 2 - bit: 1

Обновление 2: код Альваро

$conn = new mysqli('localhost', 'root', 'root','test');
//$mysqli->set_charset('utf8');
$conn->query('DROP TABLE IF EXISTS bit_test');
$conn->query('CREATE TABLE bit_test (
    my_bit BIT(1) NULL,
    my_multiple_bit BIT(8) NULL
)');
$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'0', b'111')");
$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'1', b'10000000')");

//opt 1
$q = 'SELECT cast(my_bit as unsigned) as my_bit, my_multiple_bit FROM bit_test';
//opt2 
//$q = 'SELECT my_bit, my_multiple_bit FROM bit_test';
$r = $conn->query($q);
while($row = mysqli_fetch_array($r, MYSQLI_ASSOC)){
    echo bin2hex($row['my_bit']) . '<br />';
    echo bin2hex($row['my_multiple_bit']) . '<br />';
    var_dump($row);
    echo '<br /><br />';
}

Используя PHP 5.2.12 выберите 1 и 2, оба выведите:

30
07
array(2) {
  ["my_bit"]=>
  string(1) "0"
  ["my_multiple_bit"]=>
  string(1) ""
}
31
80
array(2) {
  ["my_bit"]=>
  string(1) "1"
  ["my_multiple_bit"]=>
  string(1) "�"
}

Использование PHP 5.3.2 опция 1 выводит:

30
257175
array(2) {
  ["my_bit"]=>
  string(1) "0"
  ["my_multiple_bit"]=>
  string(3) "%qu"
}
31
257175
array(2) {
  ["my_bit"]=>
  string(1) "1"
  ["my_multiple_bit"]=>
  string(3) "%qu"
}

И вариант 2:

257175
257175
array(2) {
  ["my_bit"]=>
  string(3) "%qu"
  ["my_multiple_bit"]=>
  string(3) "%qu"
}
257175
257175
array(2) {
  ["my_bit"]=>
  string(3) "%qu"
  ["my_multiple_bit"]=>
  string(3) "%qu"
}

PHP 5.3.2 alvays печатает %qu. Есть ли в этом какой-то смысл?

Author: Community, 2013-02-27

2 answers

Вот полный пример того, как получить BIT типы столбцов:

<?php

$conn = new PDO('mysql:host=test;dbname=test', 'test', 'test');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$conn->query('DROP TABLE IF EXISTS bit_test');
$conn->query('CREATE TABLE bit_test (
    my_bit BIT(1) NULL,
    my_multiple_bit BIT(8) NULL
)');
$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'0', b'111')");
$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'1', b'10000000')");

$res = $conn->query('SELECT my_bit, my_multiple_bit FROM test');
while($row = $res->fetch(PDO::FETCH_ASSOC)){
    var_dump($row);
}

... который печатает:

array(2) {
  ["my_bit"]=>
  string(1) "0"
  ["my_multiple_bit"]=>
  string(1) "7"
}
array(2) {
  ["my_bit"]=>
  string(1) "1"
  ["my_multiple_bit"]=>
  string(3) "128"
}

Редактировать #1:

Вот мой предыдущий код, адаптированный к mysqli:

<?php

$conn = new mysqli('localhost', 'test', 'test','test');

$conn->query('DROP TABLE IF EXISTS bit_test');
$conn->query('CREATE TABLE bit_test (
    my_bit BIT(1) NULL,
    my_multiple_bit BIT(8) NULL
)');
$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'0', b'111')");
$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'1', b'10000000')");

$res = $conn->query('SELECT my_bit, my_multiple_bit FROM test');
#while($row = mysqli_fetch_array($res, MYSQLI_ASSOC)){
while($row = $res->fetch_array(MYSQLI_ASSOC)){
    var_dump($row);
}

Я получаю дополнительный элемент массива со всеми значениями, равными NULL (я не знаком с mysqli, так что, вероятно, это моя вина), но в остальном вывод идентичен. Я протестировал его в PHP/5.3.0 и PHP/5.4.5.

Я предлагаю вам попробовать мой код дословно и проверить, действительно ли вы все еще получаю %qu или что-то странное. У меня сильное чувство, что такая %qu строка может протекать откуда-то еще...

Редактировать #2:

Из дополнительной информации, я думаю, мы можем сделать следующий вывод:

  • Более ранние версии PHP извлекали столбцы BIT как есть, в виде необработанных двоичных строк (0x07 и 0x80 являются правильными числами, 7 и 128 в десятичном виде).

  • В какой-то момент было добавлено автоматическое кодирование и BIT столбцы начали извлекаться в виде десятичных знаков.

  • Версия PHP, используемая OP, вероятно, содержит ошибку в коде кодирования: %qu напоминает мне модификаторы C printf (хотя я не смог найти ее точное определение).

Учитывая различное поведение, для обеспечения согласованного вывода требуется обходной путь:

  • CAST(my_bit AS UNSIGNED) для создания десятичного числа
  • HEX(my_bit) для генерации шестнадцатеричного числа
 3
Author: Álvaro González, 2013-03-06 12:38:23

Краткий ответ

Хорошо, вот короткие и длинные ответы на мой собственный вопрос. Если вы хотите быть уверены, что столбец bit(1) извлекается как целое число, используйте следующий запрос при извлечении значений bit(1):

$q = 'SELECT (my_bit + 0) AS my_bit, (my_multiple_bit + 0) AS my_multiple_bit FROM bit_test';

Если "+0" не используется, значение столбца bit(1) обрабатывается как binary string. Это тот момент, когда я говорю себе "RTM"...

Нечто подобное можно найти здесь с помощью магии Google...

Если вы довольны быстрым решением, прекратите читать сейчас.

Теперь грязный/длинный ответ (давайте используем код Альваро)

Давайте создадим таблицу и используем четыре разных запроса с двумя версиями PHP, доступными в моей установке MAMP: 5.3.2 & 5.2.12.

$conn = new mysqli('localhost', 'root', 'root','my_db');

$conn->query('DROP TABLE IF EXISTS bit_test');
$conn->query('CREATE TABLE bit_test (
    my_bit BIT(1) NULL,
    my_multiple_bit BIT(8) NULL
)');

$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'0', b'111')");
$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'1', b'10000000')");

//q1
$q = 'SELECT (my_bit + 0) AS my_bit, (my_multiple_bit + 0) AS my_multiple_bit FROM bit_test';
//q2
//$q = 'SELECT cast(my_bit as unsigned) as my_bit, my_multiple_bit FROM bit_test';
//q3
//$q = 'SELECT HEX(my_bit) AS my_bit , HEX(my_multiple_bit) AS my_multiple_bit FROM bit_test';
//q4
//$q = 'SELECT my_bit, my_multiple_bit FROM bit_test';

$r = $conn->query($q);

//let's echo a few options
//plain gives unaltered result
//bin2hex gives hexadecimal number of an ASCII string (since) the values are treated as strings
//base16to10 gives decimal representation of hexadecimal value
//yes, the two functions are contradictionary (dependable of the query in use)
//but I'll echo their result anyway
while($row = mysqli_fetch_array($r, MYSQLI_ASSOC)){
  echo 'plain: ' . $row['my_bit'] . '<br />';
  echo 'plain: ' . $row['my_multiple_bit'] . '<br />';
  echo 'bin2hex: ' . bin2hex($row['my_bit']) . '<br />';
  echo 'bin2hex: ' . bin2hex($row['my_multiple_bit']) . '<br />';
  echo 'base16to10: ' . base_convert($row['my_bit'],16,10) . '<br />';
  echo 'base16to10: ' . base_convert($row['my_multiple_bit'],16,10) . '<br />';
  var_dump($row);
  echo '<br /><br />';
}

Вот результаты различных запросов

Что меня действительно интересует, так это простой вывод и var_dump, но вы также можете проверить вывод bin2hex и base16to10, который может быть полезен при поиске, если числа имейте некоторую связь с их соответствующими значениями: числами 0, 7, 1 и 128 (значения, сохраненные в четырех столбцах таблицы bit).

Q1 – вывод безопасной ставки идентичен в PHP 5.3.2 и 5.2.12

plain: 0
plain: 7
bin2hex: 30
bin2hex: 37
base16to10: 0
base16to10: 7
array(2) { ["my_bit"]=> string(1) "0" ["my_multiple_bit"]=> string(1) "7" }

plain: 1
plain: 128
bin2hex: 31
bin2hex: 313238
base16to10: 1
base16to10: 296
array(2) { ["my_bit"]=> string(1) "1" ["my_multiple_bit"]=> string(3) "128" }

Q2 – некоторые различия в выходных данных

Отлично работает с bit(1), но что-то не так в выводе my_multiple_bit.

PHP 5.2.12:
plain: 0
plain: 
bin2hex: 30
bin2hex: 07
base16to10: 0
base16to10: 0
array(2) { ["my_bit"]=> string(1) "0" ["my_multiple_bit"]=> string(1) "" }

plain: 1
plain: �
bin2hex: 31
bin2hex: 80
base16to10: 1
base16to10: 0
array(2) { ["my_bit"]=> string(1) "1" ["my_multiple_bit"]=> string(1) "�" } 
PHP 5.3.2
plain: 0
plain: %qu
bin2hex: 30
bin2hex: 257175
base16to10: 0
base16to10: 0
array(2) { ["my_bit"]=> string(1) "0" ["my_multiple_bit"]=> string(3) "%qu" }

plain: 1
plain: %qu
bin2hex: 31
bin2hex: 257175
base16to10: 1
base16to10: 0
array(2) { ["my_bit"]=> string(1) "1" ["my_multiple_bit"]=> string(3) "%qu" }

Q3 – вывод идентичен в PHP 5.3.2 и 5.2.12

Это также безопасный запрос для использования. Просто не забывай преобразуйте полученное шестнадцатеричное число в десятичное.

plain: 0
plain: 7
bin2hex: 30
bin2hex: 37
base16to10: 0
base16to10: 7
array(2) { ["my_bit"]=> string(1) "0" ["my_multiple_bit"]=> string(1) "7" }

plain: 1
plain: 80
bin2hex: 31
bin2hex: 3830
base16to10: 1
base16to10: 128
array(2) { ["my_bit"]=> string(1) "1" ["my_multiple_bit"]=> string(2) "80" }

Q4 – вывод довольно странный

PHP 5.2.12 отлично работает с bit(1), но я бы не стал использовать этот запрос, если есть какие-либо сомнения в используемой версии PHP или ее поведении.

PHP 5.2.12
plain:
plain: 
bin2hex: 00
bin2hex: 07
base16to10: 0
base16to10: 0
array(2) { ["my_bit"]=> string(1) "" ["my_multiple_bit"]=> string(1) "" }

plain: 
plain: �
bin2hex: 01
bin2hex: 80
base16to10: 0
base16to10: 0
array(2) { ["my_bit"]=> string(1) "" ["my_multiple_bit"]=> string(1) "�" } 
PHP 5.3.2
plain: %qu
plain: %qu
bin2hex: 257175
bin2hex: 257175
base16to10: 0
base16to10: 0
array(2) { ["my_bit"]=> string(3) "%qu" ["my_multiple_bit"]=> string(3) "%qu" }

plain: %qu
plain: %qu
bin2hex: 257175
bin2hex: 257175
base16to10: 0
base16to10: 0
array(2) { ["my_bit"]=> string(3) "%qu" ["my_multiple_bit"]=> string(3) "%qu" } 

Заключительные мысли и примечание для себя

RTM, тест и еще раз тест.

Также было бы неплохо знать наверняка, является ли этот вывод %qu эксклюзивной ошибкой PHP 5.3.2. (Или какие другие версии PHP затронутый.)

Таким образом, ответ Альваро верен в том смысле, что используйте CAST или извлекайте значения HEX из базы данных. В руководстве показан дополнительный метод "+0", который, похоже, устраняет боль от поведения разных версий PHP. Следовательно, короткий ответ находится на самом верху...

 8
Author: ZZ-bb, 2017-05-05 21:18:00