Який тип даних MySQL використовувати для зберігання булевих значень


1207

Оскільки, здається, у MySQL немає «булевого» типу даних, який тип даних ви «зловживаєте» для зберігання правдивої / неправдивої інформації у MySQL?

Особливо в контексті написання та читання з / до сценарію PHP.

З часом я використовував і бачив кілька підходів:

  • поля tinyint, varchar, що містять значення 0/1,
  • поля varchar, що містять рядки '0' / '1' або 'true' / 'false'
  • і нарешті перераховуються поля, що містять два варіанти 'true' / 'false'.

Жодне з перерахованого вище не здається оптимальним. Я, як правило, віддаю перевагу варіанту tinyint 0/1, оскільки автоматичне перетворення типів у PHP дає мені булеві значення досить просто.

Отже, який тип даних ви використовуєте? Чи є тип, призначений для булевих значень, які я не помітив? Чи бачите ви якісь переваги / недоліки, використовуючи той чи інший тип?


217
Кожен, хто читає старі відповіді на це питання, повинен розуміти, що MySQL додав трохи типу даних у версії 5. Використовуйте цю інформацію, як можливо. dev.mysql.com/doc/refman/5.0/uk/bit-type.html
smp7d


7
для поточної версії типу MYSQL Boolean доступно- dev.mysql.com/doc/refman/5.5/uk/numeric-type-overview.html перевірте це. відповідно до цього значення нуля, що вважається помилковим
DevT

7
bit(1)трохи імпортувати ** в Excel. Перехід на tinyint(1)твори.
Cees Timmerman

8
тепер у нас булеві після 5 років
V-SHY

Відповіді:


1232

Для MySQL 5.0.3 та новіших версій ви можете використовувати BIT. Посібник говорить:

Як і в MySQL 5.0.3, тип даних BIT використовується для зберігання значень бітного поля. Тип BIT (M) дозволяє зберігати M-бітові значення. M може становити від 1 до 64.

В іншому випадку, згідно з посібником MySQL, ви можете використовувати bool і boolean, які на даний момент є псевдонімами tinyint (1):

Bool, Boolean: ці типи є синонімами TINYINT (1). Значення нуля вважається помилковим. Ненульові значення вважаються істинними.

MySQL також заявляє, що:

У майбутньому випуску MySQL ми плануємо реалізувати повну обробку булевого типу відповідно до стандартних SQL.

Посилання: http://dev.mysql.com/doc/refman/5.5/uk/numeric-type-overview.html


11
Так, я хотів би або це, або CHAR (1) і зберігати "Y" / "N" або "T" / "F" і т.д. залежно від контексту. Перевага використання малого цілого типу полягає в тому, що ви отримуєте максимальну портативність через RDBMS-ес
Roland Bouman

36
Перехід на char, принаймні, на PHP, призведе до отримання більшого коду, оскільки !$booleanвін ніколи не оцінить належним чином без подальшої обробки.
Легкий фуз

10
@Pecerier Нічого, що ти не міг би гугл, але добре, я кусаю. Перш за все, будь ласка, подивіться на data0type.h. Зверніть увагу, що innodb не визначає тип BIT там. Якби воно обробляло поля BIT так, як ви описуєте, ми, безумовно, знайдемо якийсь натяк на його існування. По- друге, читайте mysqlperformanceblog.com/2008/04/23 / ... . І не соромтеся просвітити нас, які дивовижні клієнти MySQL у "marktetplace" чудово грають із полями BIT. Вони стануть у нагоді для тих, хто пропустив цю статтю без сумніву.
Roland Bouman

9
Коли я роблю вибір із стандартних командних рядків клієнтського командного рядка mysql, відображається повністю порожнім. Через це я віддаю перевагу TINYINT (1).
Користувач

8
@MikePurcell Я ненавиджу запитати, але навіщо ви хочете auto_incrementна стовпчик, що представляє булеве значення?
Кріс Хейс

248

BOOLі BOOLEANє синонімами TINYINT(1). Нуль є false, все інше є true. Більше інформації тут .


7
(1)Нічого не робить більше , ніж визначити , як відображається значення, якщо ви свідомі про розмір пам'яті , то ви хочете використовувати BITзамість
JamesHalsall

35
@JamesHalsall: Власне, BIT(1)і TINYINT(1)обидва будуть використовувати один байт сховища. До MySQL 5.0.3, BITнасправді був синонімом TINYINT. Пізніші версії MySQL змінили реалізацію BIT. Але навіть із зміною впровадження, для BITтипу даних все ще немає переваги «розмір пам’яті» (принаймні, для InnoDB та MyISAM; інші двигуни для зберігання даних, наприклад, NDB, можуть мати оптимізацію пам’яті для кількох декларацій стовпців BIT.) Більш важливим питанням є те, що деякий клієнт бібліотеки не розпізнають або належним чином обробляють повернені BITстовпці даних. А TINYINTпрацює краще.
spencer7593

5
У посібнику MySQL 5.0 чітко сказано, що булеве значення дорівнює 1 або 0. Фраза "все інше є true" не відповідає дійсності.
Вальтер

7
@Walter: Насправді це правда, пояснень дещо бракує. Коротко, в булевому контексті, вираз може оцінювати NULL, FALSE або TRUE. У операторі MySQL вираз, що оцінюється в булевому контексті, спочатку оцінюється як ціле число (десяткові та поплавкові значення округляються, рядки перетворюються звичайним химерним способом. MySQL перетворює рядки в цілі числа). NULL, очевидно, NULL (ні ІСТИНА, ні ЛЖА). Ціле значення 0 обробляється як FALSE, а будь-яке інше ціле значення (1, 2, -7 тощо) оцінюється як ІСТИНА. Для сумісності ми імітуємо цю логіку / керованість
булевим

4
@Walter: Це легко перевірити, наприклад SELECT 'foo' AS bar FROM dual WHERE -7. Вираз -7 оцінюється в булевому контексті, і запит повертає рядок. Ми можемо протестувати з 0 або будь-яким виразом, який оцінює ціле значення 0, і жоден рядок не повертається. Якщо вираз у пункті WHERE оцінює будь-яке ненулеве ціле значення, відмінне від нуля, вираз є ІСТИНИМ. (Я вважаю, що знаки десяткових і поплавкових значень отримують "округлення" до цілого числа, наприклад, WHERE 1/3оцінює до WHERE 0. Ми отримуємо той же результат WHERE 'foo', що і рядок, оскільки рядок 'foo'також оцінюється до цілого значення 0.
spencer7593

71

Це елегантне рішення, яке я дуже ціную, оскільки використовує нульові байти даних:

some_flag CHAR(0) DEFAULT NULL

Щоб встановити його як істинне, встановити some_flag = ''та встановити на false, встановити some_flag = NULL.

Потім для перевірки на справжність, перевірте, чи є деякий_флаг IS NOT NULL, а для перевірки на помилковий - перевірте, чи є деякий_флаг IS NULL.

(Цей метод описаний у «Високопродуктивній MySQL: оптимізація, резервне копіювання, реплікація та багато іншого» Джона Уоррена Ленца, Барона Шварца та Аржена Ленца.)


3
химерний трюк! це корисно, якщо робота з MySQL <5 і, можливо, навіть легший слід, ніж BIT, однак, намагаючись дотримуватися конвенції та трохи менше накладних обчислень (логіка проти точного значення), я б сказав, що BIT - це кращий шлях.
zamnuts

59
Це може бути "швидким", але це обтяжує дані таким чином, щоб будь-який новий розробник не мав уявлення про те, що означає стовпець.
Ріхтхофен

5
Тут використовується така ж кількість байтів, що і BIT (1)
ITS Alaska

25
Удачі, щоб отримати ORM, щоб добре відобразити це.
Крейг Лабенц

4
Я погоджуюся з @Richthofen, і мені важко уявити ситуацію, в якій я б коли-небудь виступав за використання цього рішення. Однак, якщо вона буде використана, то вказівка ​​як COMMENTу визначенні стовпця, що NULLвказує на помилкове та ''вказує на істинність, може піти дуже незначним шляхом до подальшого розуміння.
eggyal

34

Якщо ви використовуєте тип BOOLEAN, це є псевдонімом TINYINT (1). Це найкраще, якщо ви хочете використовувати стандартизований SQL і не заперечуйте, що поле може містити значення поза діапазоном (в основному все, що не дорівнює 0, буде "правдою").

ENUM ('False', 'True') дозволить вам використовувати рядки у вашому SQL, а MySQL буде зберігати поле внутрішньо як ціле число, де 'False' = 0 і 'True' = 1 на основі порядку, за яким вказано Enum .

У MySQL 5+ ви можете використовувати поле BIT (1) для позначення 1-розрядного числового типу. Я не вірю, що це фактично використовує менше місця у сховищі, але знову дозволяє обмежити можливі значення до 1 або 0.

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


8
Ваше зауваження щодо ENUM не відповідає дійсності: спробуйте CAST (yourenumcol AS UNSIGNED), і ви помітите, що False буде 1, а True - 2. Іншою проблемою ENUM є те, що вставити занадто легко '' (порожній рядок ). Я б не рекомендував це використовувати.
Роланд Буман

4
На мій досвід, використання поля BIT (1) з PHP-коду було дещо проблематичним. TINYINT (1) був набагато простішим і створив більш читабельний код.
M-Peror

1
@ M-Peror - "використання поля BIT (1) з PHP-коду було трохи клопітно" ... жоден каламбур не призначався. :) Але, так, я згоден. Я пам’ятаю, що TINYINT (1) теж було легше ... просто не можу пригадати, чому. У когось ще є думки з цього приводу? BIT (1) здається приємнішим на поверхні, тому що ви можете обмежити 0 або 1. Я думаю, що BIT іноді трактувались як бінарні дані (залежно від мови програмування та драйвера / бібліотеки); тоді як до TINYINT трактували як про число.
BMiner

2
@BMiner - ха-ха, це було справді ненавмисно, цього не помічав :) Але дійсно, якщо я добре пам’ятаю, бітове поле трактувалося як щось бінарне, тоді як крихітний склад було легше трактувати як число і через це легше використання в (булевому) виразі.
M-Peror

34

На це питання відповіли, але я подумав, що я заробляю 0,02 дол. Я часто використовую CHAR(0), де '' == true and NULL == false.

З MySQL Документи :

CHAR(0)також досить приємно, коли вам потрібен стовпець, який може приймати лише два значення: Стовпець, який визначений як CHAR(0) NULLзаймає лише один біт і може приймати лише значення NULLта ''(порожній рядок).


16
мм, це схоже на те, щоб попросити неприємностей, якщо ти як я. Я маю на увазі, залежно від мови це може бути занадто легко, щоб не помітити різницю між NULL та '' (наприклад, PHP).
Роланд Буман

3
З точки зору економії місця (кількість байтів, які використовуються для відображення булевих даних), такий підхід є явним переможцем. Це економить байт над TINYINT. Мінусом (як зазначають деякі коментарі) є те, що у деяких клієнтів можуть виникнути труднощі розрізняти NULL і порожню рядок. Навіть деякі реляційні бази даних (наприклад, Oracle) не відрізняють між рядком нульової довжини та NULL.
spencer7593

3
Це дуже розумно! Раніше писав розумний код, тепер уникаю цього, як чума. Тепер я хочу, щоб мій код мав кришталево чіткий намір, а не просто правильну поведінку. Моя порада? Робіть це лише в тому випадку, якщо ви хочете заплутати кожного, хто має підтримувати код / ​​базу даних. Наприклад, у PHP обидва ''і nullє фальшивими значеннями.
CJ Dennis

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

18

Я використовую TINYINT (1) для зберігання булевих значень у Mysql.

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

http://dev.mysql.com/doc/refman/5.0/uk/other-vendor-data-types.html


17

Біт вигідний порівняно з різними байтовими параметрами (tinyint, enum, char (1)), якщо у вас є багато булевих полів. Одне бітове поле все ще займає повний байт. Дві бітні поля вписуються в той самий байт. Три, чотири, п’ять, шість, сім, вісім. Після цього вони починають заповнювати наступний байт. Зрештою, економія настільки мала, є тисячі інших оптимізацій, на які слід зосередитися. Якщо ви не маєте справу з величезною кількістю даних, ці кілька байтів не збираються багато. Якщо ви використовуєте біт з PHP, вам потрібно ввести значення, що надходять і виходять.


1
+1 для коментаря на клавіатурі. Щоб додати до цього під час роботи з мовами програмування, уникайте використання методів лінивого програмування на користь послідовності. Використовуйте однакові оператори замість просто рівних. У випадку PHP, якщо ($ var == "") буде істинним для 0, false, null, undefined та "". для тестування всіх значень найчастіше найкраще використовувати if (true === empty ($ var)), оскільки це також уникне невизначених помилок. Ви також повинні перевірити тип даних, з яким ви працюєте, якщо (is_int ($ var) && $ var === 0) або ввести його, щоб змусити його стати конкретним типом даних (int) $ var для завдання.
fyrye

@Тир це правда для MySQL в тій же мірі, що і для MSSQL? Я мігрую нову програму, яка ще не перейшла у виробництво з MSSQL до MySQL. Я не використовую PHP, а конвертую C # на Java 8. З огляду на те, що Java є сильно набраною мовою, я не переживаю за обробку типів ... просто всі бітові прапори, які переміщуватимуться з одного байта до 8 прапорів до 1 байт кожного прапора із заданим TINYINT (1). Чи знаєте ви будь-яку документацію на цю тему для MySQL?
Zack Jannsen

1
@Thor Провівши глибші дослідження, зрозуміло, якою має бути відповідь. Зміни відбуваються, і ми спостерігали покращення в роботі. Знайте свою мову, яка буде міститись у шарі додатків / доступу до даних, і знайте, що ваша бібліотека підтримує. Зараз я використовую Java, і BIT (1) є рекомендованим вибором для таких бібліотек, як Hybernate та використання JDBC. Ось URL [див. Таблицю 5.2]: dev.mysql.com/doc/connector-j/en/…
Zack Jannsen

12

Поки MySQL не реалізує бітовий тип даних, якщо обробка по-справжньому натиснута на простір та / або час, наприклад, з транзакціями з високим обсягом, створіть поле TINYINT, що вимагається bit_flagsдля всіх ваших булевих змінних, та замаскуйте та перенесіть потрібний бітовий біт у свій SQL запит.

Наприклад, якщо ваш лівий біт представляє ваше поле bool, а 7 найправіших бітів не представляють нічого, то ваше bit_flagsполе дорівнюватиме 128 (двійкові 10000000). Маскуйте (прихойте) сім найправіших бітів (за допомогою оператора побітових розрядів &) і змістіть 8 біт на сім пробілів вправо, закінчуючи 00000001. Тепер усе число (що в даному випадку становить 1) - це ваше значення.

SELECT (t.bit_flags & 128) >> 7 AS myBool FROM myTable t;

if bit_flags = 128 ==> 1 (true)
if bit_flags = 0 ==> 0 (false)

Ви можете запускати такі твердження під час тестування

SELECT (128 & 128) >> 7;

SELECT (0 & 128) >> 7;

тощо.

Оскільки у вас є 8 біт, у вас є потенційно 8 булевих змінних з одного байта. Деякий майбутній програміст незмінно використовувати наступні сім біт, тому вам доведеться маскуватися. Не просто зміщуйтесь, інакше ви створите пекло для себе та інших у майбутньому. Переконайтеся, що у вас є MySQL робити маскування та переміщення - це буде значно швидше, ніж це робити мова веб-сценаріїв (PHP, ASP тощо). Також переконайтеся, що ви розмістили коментар у полі для коментарів MySQL для свого bit_flagsполя.

Ви знайдете ці сайти корисними під час впровадження цього методу:


7
Це здається просто жахливим способом придушити намір майбутніх програмістів. Звичайно , здається , що багато клопоту , щоб зберегти 7 байт (передбачається , що ви використовуєте всі 8 Bools в цій одній таблиці!)
так

@yep взагалі немає опушення! Напишіть документацію та коментарі MySQL, пояснюючи кожне поле таблиці (як згадується відповідь)! Запропонована стратегія розкриття MySQL виглядає суцільною, а зберігання до 16 різних булевих полів із лише парою стовпців краще, ніж 16 із них. Якщо це занадто заплутано при використанні бітових маніпуляцій, і ви віддаєте перевагу використовувати мову веб-скриптів, щоб отримати кожен булевий файл, просто збережіть його як VARCHARі виконайте процедуру розв’язки в коді (вам також не потрібно обмежувати його на 8 полів) ...
CPHPython

BITТипу існує. Дивіться dev.mysql.com/doc/refman/8.0/en/bit-type.html
dolmen

10

Мені набридло намагатися отримати нулі, NULLS та "" точно обернути цикл значень PHP, MySql та POST, тому я просто використовую "Так" та "Ні".

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


17
Якщо ви дійсно хотіли витратити стільки простору і погіршити продуктивність, ви могли б принаймні зробити CHAR (1) з Y та N варіантами.
ILikeTacos

3
У більшості реальних ситуацій існує реальна різниця між "ні" та простою відсутністю інформації. Наприклад, ви можете встановити прапорець за замовчуванням, якщо користувач ще не сказав "ні". Скільки саме місця, на вашу думку, ви економите та скільки обробку робите кожен раз, коли вам потрібно розрізняти помилкове та NULL - якщо ви навіть навіть МОЖЕТЕ розрізняти це? У світі збережених зображень та цифрового відео, біт-два економії місця абсолютно не мають значення, але чіткість та зменшена обробка справжні.
Джефф Кендалл

8
Ця відповідь не є помилковою, оскільки вона спрацює, і це не так вже й погано, як люди дають їй кредит. Для більшості проектів (тобто розміри таблиць <1мл. Рядків) Різниця в роботі між наданими рішеннями буде незначною. Я не буду скаржитися, якщо мої запити повернуться через 7 проти 5 мілісекунд ... Якщо бути справедливим, якщо ваші таблиці переростають у 10-мільйонні рядки чи більше, це, мабуть, не є кращим рішенням.
Бред

1
+1 від мене за використання типу даних ENUM. Я особисто віддаю перевагу цій позначці: ENUM ('y', 'n'). Це компактний (всього лише байт), інтуїтивно зрозумілий і добре виглядає як умова на рівні програми для всіх булевих прапорів. Ви можете використовувати його безпосередньо з полями форм HTML. наприклад, з PHP: <select name = "production"> <value value = "y" <? = $ production === 'y'? 'selected = "selected"': ''? >> Так </option> <value value = "n" <? = $ production === 'n'? 'selected = "selected"': ''? >> Ні </option> </select>
Владо

2
Lol це споглянуло моє око, але я повинен сказати, @GeoffKendall має рацію. У безлічі випадків немає необхідності в оптимальній продуктивності, і який би метод не робив роботу для вас, це правильний метод.
Мадменьо

6

Посилаючись на це посилання Boolean тип даних в Mysql , відповідно до використання програми, якщо потрібно зберігати лише 0 або 1, біт (1) є кращим вибором.


6
Це правда, що BIT(1)дозволить зберігати лише a b'0'або b'1'значення. Найбільша проблема з BITтипом даних полягає в тому, що різні бібліотеки клієнтів мають різноманітну неприємну обробку типу даних. Ознайомтеся з поведінкою в різних інструментах SQL (SQLyog, TOAD для MySQL, SQL Developer), інструментах, що "реверсують" інженерні моделі баз даних, та різних клієнтах, таких як JDBC, PHP, Perl DBI, і для гарної міри протестуйте декілька рамок ORM ( Зимова сплячка, Мібатіс, JPA). З точки зору простоти використання, TINYINT(1)чіткий переможець - сумісність інструментів / рамок / нативна підтримка .
spencer7593

Так. Він завершується залежно від структури, яка розглядається для програми. Наприклад, фреймворк PHP Phalcon не обробляє тип даних Bit
Vidz

Для запису MyBatis підтримує і BITта, і TINYINT. Перегляньте клас JdbcType MyBatis, mybatis.org/mybatis-3/apidocs/reference/org/apache/ibatis/type/…
Lucky

1
@Vidz Я даю вам ще один за згадку про BIT (1), але також хотів би вказати розробникам, які читають це - Знай свою мову, яка буде знаходитись у шарі додатків / Доступ до даних, і знайте, що ваша бібліотека підтримує. Зараз я використовую Java, і BIT (1) є рекомендованим вибором для таких бібліотек, як Hybernate та використання JDBC. Ось URL [див. Таблицю 5.2]: dev.mysql.com/doc/connector-j/en/…
Zack Jannsen

6

Оскільки MySQL (8.0.16) та MariaDB (10.2.1) реалізували обмеження CHECK, я б зараз використовував

bool_val TINYINT CHECK(bool_val IN(0,1))

Ви зможете тільки в магазині 0, 1або NULL, а також значення , які можуть бути перетворені в 0або 1без помилок , як '1', 0x00, b'1'або TRUE/FALSE .

Якщо ви не хочете дозволити NULL, додайте NOT NULLпараметр

bool_val TINYINT NOT NULL CHECK(bool_val IN(0,1))

Зверніть увагу, що ви користуєтесь TINYINT, TINYINT(1)або різниці практично немаєTINYINT(123) .

Якщо ви хочете, щоб ваша схема була сумісною вгору, ви також можете використовувати BOOLабоBOOLEAN

bool_val BOOL CHECK(bool_val IN(TRUE,FALSE))

db <> скриптова демонстрація


як щодо enum (0, 1)
santiago arizti

3
@santiagoarizti ENUM(це повинно бути enum('0', '1')- зауважте: це рядки) - це не дуже гарна ідея. Є дуже багато питань , з - за того , як вона зберігається всередині, і як нестроковие значення обробляються. Напр. 0і FALSE їх не можна зберігати. 1і TRUEстати '0'. І 2стає '1'.
Пол Шпігель

Найкраща відповідь ... для тих, хто використовує MySQL 8+
dolmen

2

Прочитавши відповіді тут, я вирішив використати bit(1)і так, це якось краще в просторі / часі, АЛЕ через деякий час я передумав і більше ніколи не буду його використовувати. Це дуже ускладнило мою розробку при використанні підготовлених заяв, бібліотек тощо (php).

З тих пір я завжди використовую tinyint(1), здається, досить добре.


3
Потрібно пояснити, яким чином це ускладнило ваш розвиток?
Chazy Chaz

@ChazyChaz він очікує true / false замість 1/0, на відміну від деяких інших dbs, таких як SQL Server. Іноді це може призвести до дивних ситуацій, коли ви думаєте, що встановите це на істину, але насправді це не відбувається.
maembe

0

Ви можете використовувати тип даних BOOL, BOOLEAN для зберігання булевих значень.

Ці типи є синонімами TINYINT (1)

Однак тип даних BIT (1) має більше сенсу зберігати булеве значення (або істинне [1], або помилкове [0]), але з TINYINT (1) легше працювати, коли ви виводите дані, запитуєте тощо. на та для досягнення сумісності між MySQL та іншими базами даних. Ви також можете перевірити цю відповідь або нитку .

MySQL також перетворює типи даних BOOL, BOOLEAN в TINYINT (1).

Далі читайте документацію

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