MySQL: разрушаем стереотипы

В последнее время часто стал натыкаться на различные рассуждения людей, по поводу того, что MySQL — это плохо, это очень плохо — потому что… а вот дальше идут описания различных фич MySQL, которые четко документированы, но пользователь их просто не знает. Кто-то добавляет в БД данные без валидации и удивляется почему они сохранились в неверном формате, а кто-то описывает кучу особенностей myIsam движка, и на этих основаниях делает вывод, что MySQL это отстой — который невозможно использовать в реальных проектах. Всю документацию прочитать невозможно, и да — я с этим абсолютно согласен, но поверьте у нас есть куча других недокументированных и не менее интересных особенностей. Давайте начнем с малого, к примеру докажем, что NULL равно нулю.

NULL это сложная структура, при чем каждая БД трактует его по своему. В MySQL нет таких извращений как в Oracle (там NULL равен пустой строке) у нас все гораздо круче. С одной стороны NULL равен нулю. Это легко доказать. Создадим простую таблицу null_equals_zero и заполним её 4 значениями с уникальной колонкой номер 2, по которой проведем группировку.
create table null_equals_zero(int_value     int,
                              group_value   int
                             )
engine = innodb;

insert into null_equals_zero
     values (null, 1), (0, 2), (NULL, 3), (0, 4);

select   distinct int_value
    from null_equals_zero
group by group_value;

Как вы понимаете данный запрос вернет нам уникальные значения первой колонки которых как мы знаем два: ноль и NULL
но каков будет результат? 0, NULL или оба значения одновременно?
+-----------+
| int_value |
+-----------+
|      NULL |
+-----------+
1 row in set (0.00 sec)

как и следовало ожидать это NULL ибо ноль и NULL в данном случае это одно и то же

Данный пример это лишь одна часть поведения NULL в спорных ситуациях, ибо хоть он и равен нулю, но так же легко можно доказать что NULL — больше единицы. Давайте рассмотрим две функции: least — которая возвращает минимальное значение из перечисленных аргументов, и elt — которая возвращает значение по индексу указанному первым аргументом. Думаю ни у кого, из тех кто читает этот пост, не возникает вопросов как именно они работают, но на всякий случай для чистоты эксперимента выполним 2 запроса:
select least(1, null) cmp_res;
+---------+
| cmp_res |
+---------+
|    NULL |
+---------+
1 row in set (0.00 sec)

select elt(null, 'Поле с индексом NULL') null_index_field;
+------------------+
| null_index_field |
+------------------+
| NULL             |
+------------------+
1 row in set (0.00 sec)

Пока как мы видим все идет по плану, NULL несравним с одной стороны, и по индексу NULL нет элементов, но давайте попробуем узнать чему равна суперпозиция данных функций?
select elt(least(1, null), '1 < null') null_is_to_big;

думаю догадливый читатель уже догадался какой будет ответ
+----------------+
| null_is_to_big |
+----------------+
| 1 < null       |
+----------------+
1 row in set (0.00 sec)

что и требовалось доказать, хотя вынужден заметить что тут есть 2 вывода, либо NULL больше 1 либо можно получить элемент массива по индексу NULL, который вроде как NULL, что и написано выше, но как знать…

Теперь займемся математикой, думаю за первый класс самое то. И так вопрос, какой знак имеет число 0. Не торопитесь с ответом, вы же уже поняли, что разработчики MySQL жуткие тролли. Давайте лучше проверим. И так. Создадим таблицу и вставим в нее два, близких к нулю значения — положительное и отрицательное.
create table signed_zero (float_value float);

insert into signed_zero(float_value)
     values (-0.1), (0.1);

select group_concat(round(float_value) separator ' не равно ') signed_zero from signed_zero group by round(float_value);

осталось узнать какой же у нуля знак по мнению разработчиков MySQL
+----------------------+
| signed_zero          |
+----------------------+
| -0 не равно 0        |
+----------------------+
1 row in set (0.00 sec)

ну собственно ничего удивительного — они тоже пока не определились

Ну пожалуй отвлечемся от математики и перейдем к невозможным объектам. Оказывается в MySQL есть объекты, которые нельзя создать (любителям кавычек посвящается). Давайте попробуем сделать таблицу с именем already_exists.
Начнем со справочника (что за таблица без внешнего ключа).
create table `dictionary_one` (`dict_id` int(10) primary key)
engine = innodb;

create table `already_exists`(
  `pk_id`             int(10) primary key,
  `ref_dict_one_id`   int(10),
  constraint `Already_exists_ibfk_1` foreign key(`ref_dict_one_id`) references `dictionary_one`(`dict_id`)
);

Вроде все пока идет как надо. Теперь — добавим ещё одну колонку ссылающуюся на другую таблицу.
create table `dictionary_two` (`dict_id` int(10) primary key)
engine = innodb;

alter table `already_exists` add column `ref_dict_two_id` int(10), add foreign key `Already_exists_ibfk_2`(`ref_dict_two_id`) references `dictionary_two`(`dict_id`);

Ошибок синтаксиса нет, все сделано верно
но ответ сервера вас разочарует
ERROR 1050 (42S01): Table './test/already_exists' already exists
1 row in set (0.00 sec)

говорит уже есть такая таблица, а все почему — имя неправильное, так и написано в деталях если показать статус движка InnoDB
Error in foreign key constraint creation for table `test`.`already_exists`.
A foreign key constraint of name `trans`.`Already_exists_ibfk_1` already exists. (да ну! я же назвал констрейнт Already_exists_ibfk_2)
Workaround: name your constraints explicitly with unique names. (да-да я смотрю КЭП не дремлет)
InnoDB: Renaming table `test`.`#sql-37fc_3` to `test`.`already_exists` failed!
а все почему? правильно использование кавычек до добра не доводит — где-то в движке их учли а где-то нет. Так что не судьба нам создать таблицу с имененм already_exists ибо она already exists

Помнится с введением IPv6 на всех форумах гремел вопрос. Какой тип использовать для хранения IP адреса? Звучали разные предположения: DECIMAL(39), 2хbigint(20), binary, varchar. Но для чего нам компромиссы? Ведь все знают что bigint не ограничивается лишь 20 знаками. Как вы не знали? ну что ж это тоже легко доказать.
create table new_unlimited_table
as
  select cast(substr(repeat(' ', 21848), 10) as signed integer) new_bigint_field;

select column_type
  from information_schema.columns
 where table_name = 'new_unlimited_table' and table_schema = database() and column_name = 'new_bigint_field';


что ж выясним сколько знаков у нас есть
+---------------+
| column_type   |
+---------------+
| bigint(65535) |
+---------------+
1 row in set (0.00 sec)

круто? теперь можете попращаться с репликацей и всеми последующими дампами, а bigint как был bigint'ом так им и останется

То что результат запроса не должен зависеть от последовательности добавления данных в таблицу — это вроде очевидно. Очевидно для всех, но не для нас. Мы не ищем легких путей. Попробуем сделать следующее: запишем в таблицу всего 2 строки. В начале в прямой последовательности потом в обратной, и попробуем их 2 раза выбрать один и тем же запросом:
create table data_ordering (varchar_value varchar(10));

insert into data_ordering
     values (''), ('string');

select *
  from data_ordering
 where 'string' regexp varchar_value;
+---------------+
| varchar_value |
+---------------+
| string        |
+---------------+
1 row in set (0.00 sec)


Пока все верно и без обмана, действительно только одна строка удовлетворяет нашему условию. Теперь в обратном порядке.
delete from data_ordering;

insert into data_ordering
     values ('string'), ('');

select *
  from data_ordering
 where 'string' regexp varchar_value;

те же строки — тот же запрос
осталось выяснить сколько строк из 2-х удовлетворяют тому же критерию
+---------------+
| varchar_value |
+---------------+
| string        |
|               |
+---------------+
2 rows in set (0.00 sec)

о! точно две… а первый раз?… одна? аааа ну да я же данные в другом порядке вставил, больше не буду, извините…


В общем к чему я все это? Поверьте подвоха от разработчиков можно ждать откуда угодно, и то что поведение MySQL соответствует документации — это хорошо, гораздо хуже когда все наоборот. С наступающим!
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 125

    –191
    Если этот комментарий наберет 200 плюсов я станцую ганнам на красной площади. С наступающим
      +57
      Если не наберет — адекватность аудитории хабра в очередной раз подтвердится.
        –57
        Если не наберет, то мне не придется покупать билет на самолет из Мурманска
          +11
          Сударь, не позорьте наш Кольский полуостров…
          +5
          Вы бы еще у MySQL простым на вид запросом спросили, танцевать или нет на Красной площади :)
          +22
          А если двести минусов?
            +21
            Я думаю пойдет и будет дальше менять статусы вконтакте :)
          +6
          Если честно, хотелось бы чуть более разжеванных примеров.
            +13
            И так вопрос, какой знак имеет число 0. Не торопитесь с ответом, вы же уже поняли, что разработчики MySQL жуткие тролли.

            Это не разработчики MySQL тролли, а разработчики стандарта IEEE 754: en.wikipedia.org/wiki/Signed_zero

            Результат ROUND(-0.1) в MySQL — это фактически значение, которое возвращает glibc-шная функция rint(-0.1). Которая действительно возвращает ноль со знаком минус.
              –2
              Спасибо за информацию, но -0=+0=0 значит лишних кортежей при группировке возникать не должно.
                +5
                Нет, +0 и -0 это разное. По крайней мере на один бит точно должны отличаться, сейчас посмотрю IEEE 754…
                  –1
                  Угу это и приходится объяснять бизнесу когда у них в отчетах 2 строки 0 с разным тоталом :) вы не про стандарт думайте а про конечного пользователя.
                    +23
                    Лучше себе объясните зачем вы для денежных вычислений используете числа с плавающей точкой.
                      –6
                      Можете составить такой же пример с целыми числами поделив их. Такой же результат должен быть, к сожалению не могу проверить уже. Float в примере просто для простоты восприятия.
                        0
                        деление целых чисел даёт плавающую точку же. используйте NUMERIC
                        0
                        Для дробной части суммы?
                          +1
                          хранить в неделимых еденицах? копейки, центы и т.д.
                            0
                            Судя по количеству плюсов комментария выше я, вероятно, чего-то не знаю или не понимаю. Объясните кто-нибудь, пожалуйста, почему нельзя использовать естественное представление данных с дробной частью? Зачем разносить на две колонки целая-дробная часть?
                              0
                              Кто говорит про разнесение? Одна колонка. Целочисленная. Нужно сохранить $120.99, записываем — 12099.
                                0
                                Хорошо, пусть так. Но зачем?
                                  0
                                  меньше потерь в математических операциях. www.databasesandlife.com/store-currency-amounts-as-number-of-cents-pence-etc/
                                    +1
                                    en.wikipedia.org/wiki/Floating_point#Accuracy_problems

                                    # Пример на php (прочие языки таковы же)
                                    ustimenko@home:~$ php -r 'var_dump((1 - 0.7) == 0.3);'
                                    bool(false)
                                    # Ибо
                                    ustimenko@home:~$ php -d precision=32 -r 'var_dump((1 - 0.7), 0.3);'
                                    float(0.30000000000000004440892098500626)
                                    float(0.29999999999999998889776975374843)
                                    
                                      +1
                                      Стоит заметить, что почти во всех ЯП есть типы для точной работы с floating point числами, но это естественно медленнее чем работа с целыми числами.
                                        0
                                        Примеры в студию — желательно тупейшие. Можно и те и те.
                                          0
                                          Примеры скорости или типов данных?
                                            0
                                            А мне типов, я не знаю как можно работать с floating point точно.
                                              0
                                              В пхп не скажу. Но в ruby, java есть BigDecimal.

                                              1.9.3p327 :007 > BigDecimal.new(1, 2) - BigDecimal.new(0.7, 2) == BigDecimal.new(0.3, 2)
                                               => true 
                                              1.9.3p327 :008 > 1 - 0.7 == 0.3
                                               => false 
                                              
                                              
                                                0
                                                еще в руби есть тип Rational и библиотека mathn.

                                                1.9.3p327 :021 > Rational(0.55)
                                                 => (2476979795053773/4503599627370496) 
                                                


                                                Работает странно, но точно :)
                                                  0
                                                  Оно работает из-за округления, и можно получить такие же погрешности:

                                                  BigDecimal.new(1, 2) - BigDecimal.new(0.7, 2) == BigDecimal.new(0.2999, 2) # true 
                                                    0
                                                    ну вы же должны расчитывать с какой точностью будете работать. если это деньги, то берем точность 6 и все.
                                                      0
                                                      Да и опять же есть Rational (который быстрее BigDecimal раза в 2)

                                                      Rational(1) - Rational(0.7) == Rational(0.29999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999)
                                                       => false 
                                                      
                                                      
                                                    0
                                                    В php нету из коробки, но можно заюзать java`вскую через extension кастомный.
                                                      0
                                                      Есть из коробки. BC math.
                                                        0
                                                        oops, точно!

                                                        Хотя выглядит по-уродски по сравнению с более православными руби и питоном:

                                                        ustimenko@home:~$ php -r 'var_dump(0 == bccomp(bcsub(1, "0.7", 2), "0.3", 2));'
                                                        bool(true)
                                                        


                                                        Причем ещё надо явно precision указывать — пипец…
                                                0
                                                Ruby
                                                1.9.3p327 :010 > Benchmark.measure { BigDecimal.new(1, 2) - BigDecimal.new(0.7, 2) == BigDecimal.new(0.3, 2) }
                                                 =>   0.000000   0.000000   0.000000 (  0.000089)
                                                 
                                                1.9.3p327 :011 > Benchmark.measure { 1 - 0.7 == 0.3 }
                                                 =>   0.000000   0.000000   0.000000 (  0.000015)
                                                


                                                Как видите почти в 6 раз медленнее
                                                  0
                                                  Однострочники:

                                                  ustimenko@home:~$ ruby -e 'print(1 - 0.7 == 0.3); print("\n");'
                                                  false
                                                  ustimenko@home:~$ ruby -e 'require "bigdecimal"; print(BigDecimal.new("1") - BigDecimal.new("0.7") == BigDecimal.new("0.30000")); print("\n");'
                                                  true
                                                  
                                                  ustimenko@home:~$ python -c 'print (1 - 0.7 == 0.3)'
                                                  False
                                                  python -c 'from decimal import *; print (1 - Decimal("0.7") == Decimal("0.3"))'
                                                  True
                                                  
                              +1
                              да первый бит всегда отвечат за минус — если первый бит равен 1 то минус есть или наоборот — 0 то +
                                0
                                -0 равен 0 судя из примера: группировка была по -0 и 0 т.к. в поле group_concat видим все 2 значения, значит они равны. Или я что то просмотрел?
                                0
                                Согласен, лишних кортежей быть не должно. Как выяснилось, это проблема HASH индексов в MEMORY storage engine: bugs.mysql.com/bug.php?id=67978
                                  0
                                  Спасибо за дельный комментарий, это действительно оно, теперь становится понятно где ещё это может всплыть. Автор бага вы, если не секрет?
                                    0
                                    К счастью, не я :) Баг был с незапамятных времён. Подозреваю, что с самой первой реализации HEAP и HASH индексов.
                                      0
                                      Я имел ввиду кто именно завел баг, а не кто написал код :) но ответ тоже хороший :D из области: «Казань брал, Астрахань брал, Шпака не брал!»
                                        +2
                                        Я переделывал обработку чисел с плавающей точкой в MySQL 5.5. Поэтому и заинтересовался. Баг зарепортил я по мотивам нашего обсуждения.
                              0
                              А что документация говорит по этому поводу?

                              
                              CREATE TABLE `medals` (
                                `id` int(11) NOT NULL AUTO_INCREMENT,
                                `country` varchar(50) NOT NULL,
                                `event_name` varchar(50) NOT NULL,
                                `golds` int(11) NOT NULL,
                                PRIMARY KEY (`id`)
                              ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
                              
                              
                              INSERT into medals(event_name) VALUES('starting');
                              
                              Select * from medals;
                              +----+---------+------------+-------+
                              | id | country | event_name | golds |
                              +----+---------+------------+-------+
                              |  3 |         | starting   |     0 |
                              +----+---------+------------+-------+
                              1 row in set (0.00 sec)
                              
                              
                              


                              Или на такой пример:

                              SELECT 124124/0;
                              +----------+
                              | 124124/0 |
                              +----------+
                              |     NULL |
                              +----------+
                              1 row in set (0.00 sec)
                                +1
                                И первый и второй случай это стандартное поведение если не указывать дополнительных режимов работы БД. Посмотрите SQL_MODE.
                                  +3
                                  mysql> SET sql_mode='STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO';
                                  Query OK, 0 rows affected (0.00 sec)
                                  
                                  mysql> SELECT 124124/0;
                                  +----------+
                                  | 124124/0 |
                                  +----------+
                                  |     NULL |
                                  +----------+
                                  1 row in set, 1 warning (0.00 sec)
                                  
                                  mysql> SELECT @@SESSION.sql_mode;
                                  +-----------------------------------------------------------------------------+
                                  | @@SESSION.sql_mode                                                          |
                                  +-----------------------------------------------------------------------------+
                                  | STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO |
                                  +-----------------------------------------------------------------------------+
                                  1 row in set (0.00 sec)
                                  


                                  Не поскажете какой параметр фиксит это?
                                    +1
                                    Да вы правы ERROR_FOR_DIVISION_BY_ZERO на который я рассчитывал фиксит это только для DML операций согласно документации. Но опять же согласно ей же это поведение для мускуля нормально. Просто надо к нему привыкнуть и при необходимости ставить coalesce. Так же думаю надо проверить как это работает в процедурах. Там же ест обработчик деления на ноль. Он должен перехватить. Но согласитесь то о чем вы написали все знают как хорошо документированную фичу.
                                      +3
                                      Помимо документации, есть еще стандарт ANSI SQL, и он должен быть главнее документации по БД. По поводу деления на ноль, стандарт прямо говорит, что должен происходить Exception.

                                      «If the value of a divisor is zero, then an exception condition is raised: data exception-division by zero.»

                                        0
                                        А что есть «an exception condition»?
                                          0
                                          Это написано в пункте 3.3.4.1 Exceptions
                                          Вольный пересказ — команда считается неудачной, возможно надо прекратить выполнение кода и надо обязательно вывести отладочную информацию. Данные и структуры таблиц поменяться не должны.
                                            0
                                            В том то и дело, что «возможно», а значит MySQL следует стандарту.
                                      +1
                                      Когда я забываю указать поля вставки в insert или допускаю в своем коде деление на ноль, мне некого ругать кроме самого себя. А вот когда выясняется, что null is not null это уже из другой области.
                                        –1
                                        где то читал, что null это неопределенное значение и следовательно ни себе не равно и чему другому. И результат деления на 0 = неопределённое число… получается логично.
                                          +1
                                          В математике, если уже и делится на 0, то получается определенная величина тоже — бесконечность.

                                          1.0 / 0.0
                                           => Infinity


                                          Так что логики пока не видно.
                                            0
                                            Да вы что… а я всегда думал что в стандартной арифметике «Результат деления на ноль не определен». А за «бесконечность — определённая величина» вам 2 и на повторный курс 8-го класса…
                                              0
                                              Операции деления ненулевого числа на ноль не соответствует никакое действительное число.
                                              Результат этой операции считается бесконечно большим и равным бесконечности: bit.ly/gpa8nr

                                              Значение операции 0:0 (ноль деленное на ноль) неопределенно (которое я и не рассматривал).

                                              > 0.0 / 0.0
                                              => NaN
                                              > 1.0 / 0.0
                                              => Infinity
                                  –2
                                  ну уж 65535 десятичных цифр — нам точно хватит


                                  Совсем не так. Знаковый bigint хранит значения от -9223372036854775808 до 9223372036854775807, т.е. 19 знаков. Что немного меньше, чем 65535,
                                    +1
                                    Ну я как бы об этом и писал. Вы запрос ты выполнить не поленитесь. А потом посмотрите структуры созданной таблицы. И подумайте что будет при восстановлении БД из бэкапа или репликации.
                                      +1
                                      Я не совсем понимаю, о чём вы говорите. Цифра в скобках (65535) вообще к диапазону хранимых значений никакого отношения не имеет. От того, что вы укажете там 1 или 42 — данные не изменятся абсолютно никак.
                                        0
                                        А то что cast( as signed integer) на выходе дает mediumtext тоже не о чем не говорит? Конечно вы не сможете записать туда такие значения и сделать вид что это bigint.
                                          +2
                                          Я повторю ещё раз — вы как минимум вводите в заблуждение читателей, как максимум — заблуждаетесь сами, считая, что число 65535 имеет хоть какое-то влияние на хранимые данные.
                                            +1
                                            Вы вообще о чем?
                                            Я прошу БД сделать мне bigint из строки длиной 10!
                                            substr(repeat(' ', 21848), 10)
                                            А что получаю в итоге? А то что я пишу что null равно 0 или любой другой пример вас не насторожило что ли?
                                              –1
                                              Я о ваших фразах:

                                              > что ж выясним сколько знаков у нас есть
                                              +
                                              > ну уж 65535 десятичных цифр — нам точно хватит

                                              Число знаков, которые позволяет сохранить тип определяется сугубо названием типа, а не числом в скобочках.

                                              Про остальные примеры я не говорю, я с самого начала и до сих пор говорю о вашей единственной некорректной фразе.
                                                +1
                                                А по моему все выводы в этой статье некорректны это же сарказм… Вся статья. Я не пояснил истинные причины ни по одному из примеров. Тут истина только то что mysql выдает кучу не документированного бреда в самый не подходящий момент. И именно это и есть зло.
                                                  0
                                                  В случае с bigint(65535) этот «бред» документирован.

                                                  dev.mysql.com/doc/refman/5.5/en/numeric-type-attributes.html
                                                    +2
                                                    С чего вы взяли?
                                                    После данного запроса ваша реплика вылетит а дамп придется чистить руками ибо:
                                                    create table unlimited_table (new_bigint_field bigint(65535));
                                                    ERROR 1439 (42000): Display width out of range for column 'new_bigint_field' (max = 255)
                                                    

                                                    а в моей БД такие таблицы бывают ;)
                                                    show create table new_unlimited_table \G
                                                    *************************** 1. row ***************************
                                                           Table: new_unlimited_table
                                                    Create Table: CREATE TABLE `new_unlimited_table` (
                                                      `new_bigint_field` bigint(65535) NOT NULL DEFAULT '0'
                                                    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
                                                    1 row in set (0.00 sec)
                                                    
                                                    
                                                      +2
                                                      О боже.

                                                      Я повторю в третий раз: я не спорю, что дамп получится кривой, я лишь говорю, что

                                                      > ну уж 65535 десятичных цифр — нам точно хватит

                                                      некорректно в принципе, даже в ироничной статье. В особенности после «Ведь все знают что bigint не ограничивается лишь 20 знаками. Как вы не знали? ну что ж это тоже легко доказать.»

                                                      Это не доказательство, а введение в заблуждение читателя (который не знает синтаксиса).
                                                    0
                                                    «Недокументированный бред» — это всегда баги. Не стесняйтесь их репортить «своему MySQL вендору».
                                      –1
                                      В MySQL нет таких извращений как в Oracle (там NULL равен пустой строке)

                                      А по-моему это классно. Когда первый раз, ещё в школьные или около того годы, прочитал — тоже подумал: «как это так? А как мне хранить пустые строки? Ну и извращение этот ваш Оракл...» А со временем я понял, что ни разу в жизни мне не попадалась ситуация, где хранение в БД пустой строки имело бы физический смысл. Если пользователь не заполнил необязательное поле формы, или ввёл что-то, а потом удалил — значит по данному полю нет данных, т.е. логически null. Если возникает ситуация, когда по этому полю «сказать нечего», а колонка в базе обозначена NOT NULL — значит имеет место ошибка проектирования. А микс означающих на деле одно и то же «нулей», пустых строк и серий пробелов в одной колонке — вот это извращение. В результате я пришёл к тому, что всегда (разумеется, если бы попался осмысленный повод, я сделал бы исключение) на уровне прослоечного кода делаю сначала trim строки по бокам и если получаю пустую строку, то в базу пишу NULL (а если не пустую — то её (обтримленную)).
                                        +4
                                        А мне как-то не по себе. NULL не д.б. FALSE`ом.

                                        Также NULL не д.б. пустотой — это просто ничто.

                                        NULL — это когда мы не знаем чего-то, а пустая строка — это мы уже знаем, что чего-то нет.

                                        Кароче это всё равно не хорошо так — как-то не по себе что ли.
                                          0
                                          В оракле null не является тождественным булеву false. Ну и как по мне вполне логично, что пустота — это ничто.
                                          Все ваши ощущения исключительно от субъективного восприятия NULL. Для меня лично непонятно «NULL — это когда мы не знаем чего-то». Наоборот известно, что нет ничего.
                                            0
                                            Да не совсем. NULL — это когда неизвестно. Нет ничего — это как раз пустая строка или FALSE.

                                            Пример:

                                            Name: Саша
                                            Sex: NULL

                                            Какого пола у нас Саша?

                                            Или другой вариант поля — IsMale

                                            ps: Ежу ясно, что так не делают, но это конно-вакуумно абстракция.
                                              0
                                              Если Саша не указал/указала пол, то что там кроме нулла должно быть?
                                              Если у вас поле предполагает булево значение, но допускает нулл, ну извиняйте, имхо, небольшая кривизна в моделировании.
                                              И откуда такая уверенность, что False = Null? False — ложное утверждение, null — отсутствие утверждения (вполне коррелирует с пустой строкой).

                                                0
                                                Тов. Optik, я как раз об обратном и говорю!

                                                Я за то, что FALSE не есть NULL

                                                Просьба вчитаться внимательнее :)
                                                  0
                                                  Вы утверждаете, что в оракловой базе это так. Разве не об этом была ваша речь?
                                                    +1
                                                    Да нет — я про оракл вообще ничего не говорил.

                                                    Я сказал: «NULL не д.б. FALSE`ом.»

                                                    Это не конкретно про оракл/мусклуь/ё-нейм-хиа.
                                            0
                                            Вообще говоря многозначность значения NULL является достаточно старой проблемой, упоминавшейся ещё Коддом!
                                            Codd indicated in his 1990 book The Relational Model for Database Management, Version 2 that the single Null mandated by the SQL standard was inadequate, and should be replaced by two separate Null-type markers to indicate the reason why data is missing. In Codd's book, these two Null-type markers are referred to as 'A-Values' and 'I-Values', representing 'Missing But Applicable' and 'Missing But Inapplicable', respectively.[5] Codd's recommendation would have required SQL's logic system be expanded to accommodate a four-valued logic system. Because of this additional complexity, the idea of multiple Null-type values has not gained widespread acceptance in the database practitioners' domain. It remains an active field of research though, with numerous papers still being published.
                                              0
                                              Sorry, but comrade Codd confused storage with validation. If we have situation, where we should have the data but not have it — ti should be managed on app level or in case of complex DB-side solutions — in just not-null or triggers side.

                                              Inapplicable NULL is something wrong — it's same as have in one DB column for two purposes. For example we have some GOD-mode shitti app and some table with some positive number values and instead of adding new column like something_type, we start to add in this column another values but negative. It's a bad practice. I think industry did it right to leave only one-purpose NULL value.
                                                +1
                                                I think we missed that point raised by Codd.
                                                Sometime NULL means that this particular row (tuple) does not have this value by nature,
                                                sometimes — value is not known (yet), sometimes — any other value is not applicable at all.
                                                It is not a problem of validation or restriction.
                                                We can't solve that problem fundamentally by ignoring it.

                                                PS.
                                                И снова о вечной проблеме отсутствующей информации
                                                Сергей Кузнецов
                                                  0
                                                  Hmm… Do you mean the case, when we use single table for two/more classes?

                                                  Like this --> martinfowler.com/eaaCatalog/singleTableInheritance.html

                                                  ?

                                                  I just cant' understand those case like «no value by nature». Why then we have column for it??? Can you provide some eral-life example?
                                              –1
                                              Это логика такая двоичная. Была бы троичная, было бы как вам хочется.
                                                +1
                                                А разве введение NULL в стандарте уже не предусматривает «троичной логики»?
                                            +7
                                            А я думал мне одному кажется что это не фичи а баги
                                            –2
                                            Начали за здравие, кончили за упокой. Как раз ваша статья подтверждение, что MySQL это плохо:) Это круто, что на 22533 странице документации есть описание того, что константа TRUE = 0, а FALSE =1, но есть еще такая штука, как ожидаемое поведение. Во многих случаях MySQL ведет себя непредсказуемо, притом не очевидно непредсказуемо(хоть с тем же делением на ноль), и требуется долго локализовывать причину и искать в доках причину.
                                            Не скажу, что MySQL плохая, но лично я ее жутко не люблю, т.к. проблем с ней у меня возникало предостаточно, притом неочевидных. Сам предпочитаю postgresql.
                                              0
                                              Я таки не постесняюсь и скажу, что после PostgreSQL MySQL вспоминается как страшный сон.
                                              С неудобоваримой документацией, непредсказуемым поведением и жуткой консолью.
                                              Вот расскажите мне, какой профит использовать её, когда есть текущая версия postgres?
                                              0
                                              Утверждение «в Oracle NULL равен пустой строке» не совсем верно. Пустая строка равна NULL, и то по определению, а не по операции сравнения. Любое же сравнение с NULL имеет результатом NULL. То есть не true или false. И это хорошо.
                                                0
                                                Опять не соглашусь — даже 0 не равен NULL.

                                                NULL — это неизвестность, а ноль — это конкретное количество.

                                                — Сколько вешать в граммах?
                                                — Да х.з. vs. — Ноль грамм.
                                                  –1
                                                  Я упоминал ноль? Надо же.
                                                    0
                                                    Да нееет :)) Пустая строка и NULL тоже самое.

                                                    Пример:

                                                    1. Мы пришли и спросили у продавца: «Сколько стоят вот эти конфеты?» Он нам ответил: «0 руб. — они списаны».
                                                    VS
                                                    2. Мы пришли и спросили у продавца: «Сколько стоят вот эти конфеты?» Он нам ответил: «Ой, я не знаю — я тут первый день!»

                                                    Поэтому «НЕ ЗНАЮ» у нас в итоге не есть «НОЛЬ».

                                                    ps: простите за кэпс
                                                    pps: упс., опять пример про ноль — в первом варианте было «Как тебя зовут?»
                                                    ppppps: Короче это очень тонкое различие, которое не сразу осознаётся. Да и больше оно академично, нежели практично.
                                                      0
                                                      Молодой человек, вы приписываете мне то, что я не говорил, и наоборот, лишаете того, что я сказал.
                                                      На самом деле даже я допустил неточность в первом комментарии, а именно — все верно лишь для строк типа varchar2 или sql-машины. В pl\sql машине есть нюанс:

                                                      declare
                                                        a char := '';
                                                      begin
                                                        if a is null then
                                                          dbms_output.put_line( 'null' );
                                                        else    
                                                          dbms_output.put_line( 'not null' );
                                                        end if;
                                                      end;
                                                      /
                                                      
                                                      
                                                        –1
                                                        Эхх… Уважаемый товарищ,

                                                        Мне до конкретики в конкретной реализации мало интересно доходить.

                                                        Я пытаюсь объяснить что такое NULL вообще, а не только в оракле. Если мы друг-друга не поняли, то и хрен с ним тогда.

                                                        Вообще в любой системе хранения данных NULL не должен быть равен пустой строке — это моё личное мнение и не утверждение про DBMS IKS.
                                                          0
                                                          Строго говоря, пример неудачный, т.к. в oracle char не может быть «пустой строкой». Просто посмотрите его длину. Отличие действительно есть в pl/sql, но единственное и категорически не связано с char'aми:
                                                          create or replace function f_is_null(s varchar2) return varchar2 is
                                                            type tt is table of number index by varchar2(10);
                                                            vt tt;
                                                            e exception;
                                                            pragma exception_init(e,-6502);
                                                          begin
                                                            vt(s):=1;
                                                            return case 
                                                                     when s is null then 'empty' 
                                                                     else 'not empty' 
                                                                   end;
                                                          exception 
                                                            when e then return 'null';
                                                          end;
                                                          /
                                                          declare
                                                            pkey1 varchar2(10):='';
                                                            pkey2 varchar2(10):=null;
                                                            pkey3 varchar2(10):='filled';
                                                          begin
                                                            dbms_output.put_line('pkey1-'||f_is_null(pkey1));
                                                            dbms_output.put_line('pkey2-'||f_is_null(pkey2));
                                                            dbms_output.put_line('pkey3-'||f_is_null(pkey3));
                                                          end;
                                                          /
                                                          
                                                  –3
                                                  Уважаю MySQL, только он умеет троллить в ответ на попытки его затроллить.
                                                    0
                                                    Я кстати совсем недавно ввел вопрос, где мне нужно было явно узнать количество дней прошеших с начало нового времени и TO_DAYS как ни странно — вернул неправильный результат.
                                                    habrahabr.ru/qa/31239/
                                                      0
                                                      select   distinct int_value
                                                          from null_equals_zero
                                                      group by group_value;
                                                      
                                                      

                                                      Как вы понимаете данный запрос вернет нам уникальные значения первой колонки которых как мы знаем два: ноль и NULL
                                                      Я такого запроса категорически не понимаю! Что за группировка по второму полю, а дистинкт без агрегата по первому?
                                                        0
                                                        Вывести все уникальные значения для каждой группы.
                                                          0
                                                          А если подумать?
                                                          Если и подумать не помогло:
                                                          «Доказательство», что 1=2=3=4:
                                                          mysql> create table null_equals_zero(int_value     int,
                                                              ->                               group_value   int
                                                              ->                              )
                                                              -> engine = innodb;
                                                          Query OK, 0 rows affected (0.00 sec)
                                                          
                                                          mysql> insert into null_equals_zero
                                                              ->      values (1, 1), (2, 1), (3, 1), (4, 1);
                                                          Query OK, 4 rows affected (0.00 sec)
                                                          Records: 4  Duplicates: 0  Warnings: 0
                                                          
                                                          mysql> select   distinct int_value
                                                              ->     from null_equals_zero
                                                              -> group by group_value;
                                                          +-----------+
                                                          | int_value |
                                                          +-----------+
                                                          |         1 |
                                                          +-----------+
                                                          1 row in set (0.00 sec)
                                                          
                                                          
                                                          

                                                            0
                                                            Думаю этот ответ стоит откомментировать, ибо в вашей логиге заблуждение как раз из первой группы, так как вы думаете, что группировка в MySQL работает так же как и в остальных СУБД.
                                                            Рассмотрите этот пример
                                                            drop table if exists null_equals_zero;
                                                            
                                                            create table null_equals_zero(int_value     int,
                                                                                          group_value   int
                                                                                         )
                                                            engine = innodb;
                                                            
                                                            insert into null_equals_zero
                                                                 values (null, 1), (0, 2), (1, 3);
                                                            
                                                            select   distinct int_value
                                                                from null_equals_zero
                                                            group by group_value;
                                                            +-----------+
                                                            | int_value |
                                                            +-----------+
                                                            |      NULL |
                                                            |         1 |
                                                            +-----------+
                                                            
                                                            delete from null_equals_zero;
                                                            
                                                            insert into null_equals_zero
                                                                 values (0, 1), (null, 2), (1, 3);
                                                            
                                                            select   distinct int_value
                                                                from null_equals_zero
                                                            group by group_value;
                                                            +-----------+
                                                            | int_value |
                                                            +-----------+
                                                            |         0 |
                                                            |         1 |
                                                            +-----------+
                                                            


                                                            и обязательно посмотрите, что будет если группировка делается по одному полю, а выбирается другое.
                                                              0
                                                              Еще раз хорошенько подумайте… Нет у вас тут никакой группировки! У вас нет аггрегата! Вы используете исключительно кривой запрос с багом.
                                                                0
                                                                Вас не смутило даже то что при изменении порядка вставки элементов поменялся результат запроса?
                                                                  –2
                                                                  А вас не смущает писать идиотские невалидные запросы? причем внимательно посмотрите на то, что сами написали:
                                                                  Как вы понимаете данный запрос вернет нам уникальные значения первой колонки которых как мы знаем два: ноль и NULL
                                                                    +1
                                                                    Очень даль что вы считаете меня идотом, а мой пост "имбанутым гавном", о чем вы почему-то не постеснялись написать в твиттере, но постеснялись сказать мне лично в комментариях в этом топике, но я считаю кокретно с вашим вопросом надо разобраться. Новый год все таки. Надо быть позитивнее :)
                                                                    Я такого запроса категорически не понимаю! Что за группировка по второму полю, а дистинкт без агрегата по первому?

                                                                    В отличии от Oracle, в котором вы видимо привыкли работать, MySQL допускает ряд фривольностей в написании group by запросов. К примеру если выбрать поля, по которым не произведена группировка, то MySQL возьмет для значения этого поля — первое попавшееся ему значение в таблице. Т.е. тот результат примера, который вы привели далее немного подумав — вполне ожидаем. Вы произвели группировку по полю с единственным значением, а выбрали поле, по которому группировка не производилась. Собственно MySQL взял первое что ему попалось и вывел в результируещем resultset'е. Я же делаю немного другое. Я провожу группировку по полу в котором 4 значения. Так что у меня получается 4 кортежа. Далее я просто выбираю уникальные поля из всего того что у меня получилось, опуская собственно поля группировки. Воспроизведем эти шаги на значения отличных от NULL.
                                                                    получим 0 и 1
                                                                    drop table if exists null_equals_zero;
                                                                    create table null_equals_zero(int_value     int,
                                                                                                  group_value   int
                                                                                                 )
                                                                    engine = innodb;
                                                                    
                                                                    insert into null_equals_zero
                                                                         values (1, 1), (0, 2), (1, 3), (0, 4);
                                                                    
                                                                    select   int_value
                                                                        from null_equals_zero
                                                                    group by group_value;
                                                                    +-----------+
                                                                    | int_value |
                                                                    +-----------+
                                                                    |         1 |
                                                                    |         0 |
                                                                    |         1 |
                                                                    |         0 |
                                                                    +-----------+
                                                                    4 rows in set (0.00 sec)
                                                                    
                                                                    select   distinct int_value
                                                                        from null_equals_zero
                                                                    group by group_value;
                                                                    +-----------+
                                                                    | int_value |
                                                                    +-----------+
                                                                    |         1 |
                                                                    |         0 |
                                                                    +-----------+
                                                                    2 rows in set (0.00 sec)
                                                                    


                                                                    теперь же попробуем пример из статьи
                                                                    получим только одно значение
                                                                    drop table if exists null_equals_zero;
                                                                    create table null_equals_zero(int_value     int,
                                                                                                  group_value   int
                                                                                                 )
                                                                    engine = innodb;
                                                                    
                                                                    insert into null_equals_zero
                                                                         values (null, 1), (0, 2), (null, 3), (0, 4);
                                                                    
                                                                    select   int_value
                                                                        from null_equals_zero
                                                                    group by group_value;
                                                                    +-----------+
                                                                    | int_value |
                                                                    +-----------+
                                                                    |      NULL |
                                                                    |         0 |
                                                                    |      NULL |
                                                                    |         0 |
                                                                    +-----------+
                                                                    4 rows in set (0.00 sec)
                                                                    
                                                                    select   distinct int_value
                                                                        from null_equals_zero
                                                                    group by group_value;
                                                                    +-----------+
                                                                    | int_value |
                                                                    +-----------+
                                                                    |      NULL |
                                                                    +-----------+
                                                                    1 row in set (0.00 sec)
                                                                    

                                                                    то, что лежит в БД первее 0 или NULL, но не оба значения сразу, что доказывает предыдущий мой пример из комментария.

                                                                    Я рискну предположить, что тут дело в оптимизаторе, который умеет оптимизировать конструкции типа group by если так же в условии встречается distinct или же limit (с ним тоже есть немало интересных багов, но они сложнее в понимании по этому я их тут не стал приводить, а привел только те, что можно быстро понять).
                                                                    Если вам непонятет синтаксис, не стоит говорить что это идиотский запрос, ибо парсер отлично этот запрос отработал и даже вернул результат, что уже говорит о том, что запрос написан верно. Стоит все таки действительно немного подумать.

                                                                    З.Ы. а по поводу неверной оценки статей я с вами частично согласен, ибо на хабре действительно есть множество интересных, по моему мнению технических статей, которые были недостаточно оценены сообществом, но только в этом…
                                                                      –2
                                                                      Как меня поражает все-таки наглая попытка увильнут и как-то откреститься от своих же слов и действий. Внимательно смотрите что я процитировал в исходном комменте.
                                                                      Пройдемся спокойно по списочку:
                                                                      1. Вы пишете кривой недокументированный запрос
                                                                      2. Снабжаете его неверной интерпретацией
                                                                      3. Получаете кривые данные кривого запроса
                                                                      4. Пытаетесь сделать из этих данных какой-то совершено не взаимосвязанный вывод.
                                                                      5. В выводе косвенно заявляете о том, что все написанное выше это ошибки разработчиков mysql, но не уточняете, что как минимум этот ваш запрос — это именно ваша ошибка.

                                                                      Я несколько раз пытался намекнуть, а после уже прямым текстом сказал, что запрос вы пишете невалидный. Багом является то, что не выдает ошибки при запросе об отстутствии агрегата. Не пытайтесь анализировать на невалидных запросах, что вы постоянно пытаетесь делать как и в случаете с enum.
                                                                        +1
                                                                        1. запрос не кривой, он успешно работает, и даже всегда за исключением одного случая, возвращает корректные данные.
                                                                        2. интерпретация запросов неверна в каждом из моих комментариев, но SQL не врет ибо в данном конкретном случае NULL действительно неотличим от 0
                                                                        3. см 2 пункт выше и пример с 0 и 1, чем они кривой?
                                                                        4. во всей стаье выводы совершенно бредовые, неужели вы этого не заметили?
                                                                        5. все это является багами MySQL если вы захотите вы даже сможете найти их номера. Когда я получал данные ошибки я сознательно не заводил баги, ибо пробежавшись по bugs.mysql.com находил очень похожие. Все эти баги не решены до сих пор. Если хотите можете поискать, вон выше сам разработчик MySQL как раз завел новый баг на основании нашего обсуждения этих фич. Вот он bugs.mysql.com/bug.php?id=67978. И поверьте каждый описанный случай основан именно на баге. Конечно сами запросы в которых они возникли гораздо сложнее, но для статьи я переделал их, для того чтобы максимально упростить.
                                                                          –1
                                                                          Чтобы не продолжать бессмысленный диспут, приведите пруф на документацию, где описано поведение при указании поля вне агрегатов в группировках
                                                                              –1
                                                                              А внимательнее? Где там детерминировано поведение дистинкта с этим расширенным поведением? Вот сортировка описана, а дистинкт? То есть вы успешно нашли способ стрельнуть себе в ногу, поздравляю!
                                                                                +1
                                                                                Э… Там как бы и про лимит не написано, и про остальные сотню комманд которые там можно впихнуть тоже не слова.
                                                                                Подумайте: почему при любых значениях кроме NULL и 0 этот запрос работает верно? Вот вы упрямы. Вы свои ошибки в сужениях никогда не признаете?
                                                                                Заметьте, чуть выше один комментатор написал про bigint, и после длительных баталий в личке, я наконец-то понял что он имеет ввиду, и что это действительно может запутять неопытного читателя, и убрал указанный им пунк. Вы же упрямо не хоите верить ни одному запросу, который я привожу вам в качестве аргументации.
                                                                                Вы даже не знали про cинтаксис комманды group by! И упорно настаиваете на том, что вы правы, делая это самым хамским образом у всех за спиной… Не надо путать и оскорблять ни меня ни читателя, пожалуйста.
                                                                                  0
                                                                                  Во-первых, раз используете расширение с нестандартным поведением да еще и прямо противоречащим ansi-стандарту, то должны отталкиваться от документации. Во-вторых, один из известных и применяемых в разных субд алгоритмов дистинкта — это сортировка либо значений/хэшей, что должно было вселить сомнения в валидности.
                                                                                  За спиной? Имхо вполне себе публично, только вот перевирать мои слова не надо.
                                                                  0
                                                                  Вы используете исключительно кривой запрос с багом.

                                                                  Странно я вроде так и писал в своей статье, очень жаль что вы приняли все за чистую монету. Конечно баги на то и баги, что не везде встречаются. Я просто сделал подборку из тех багов с которыми пришлось столкнуться на протяжении последних трех лет работы…
                                                                    0
                                                                    Странно я вроде так и писал в своей статье
                                                                    Вы нигде не указали, что ваш запрос невалиден! Неудивительно, что вы получаете недокументированный результат на запрос невалидный с точки зрения той же документации.
                                                                  0
                                                                  уберите в запросе дистинкт-может быть это вас натолкнет на верный путь. хотя вам проще почитать про стандарт сиквела
                                                                    0
                                                                    Ваше нежелание почитать как конкретно реализован group by в mysql не позволяет мне продолжать с вами дискуссию. По сему во избежание холиваров предлагаю каждому из нас остаться при своем мнении.
                                                                      0
                                                                      Ваше нежелание думать при написании запросов не позволяет мне продолжать с вами дискуссию.
                                                                    0
                                                                    Немного помогу в споре. Запрос:

                                                                    select   distinct int_value
                                                                        from null_equals_zero
                                                                    group by group_value;
                                                                    

                                                                    изначально некорректный, но отрабатывается из-за специфических особенностей MySQL. Вот так можно проверить валидность запроса:

                                                                    SET sql_mode = 'ONLY_FULL_GROUP_BY';
                                                                    
                                                                    SELECT distinct int_value
                                                                    FROM null_equals_zero
                                                                    group by group_value;
                                                                    
                                                                    Error Code: 1055. 'test.null_equals_zero.int_value' isn't in GROUP BY
                                                                    

                                                                    0
                                                                    И ещё, то что один равно двум доказывается несколько иным способом.
                                                                    Как-то так
                                                                    drop table if exists two_numbers;
                                                                    
                                                                    create table two_numbers (
                                                                      number_value enum('1','0')
                                                                    );
                                                                    
                                                                    insert into two_numbers(number_value)
                                                                         values ('0'), ('1');
                                                                    
                                                                    select concat(max(number_value), ' = ', max(number_value + 0)) one_equals_two from two_numbers;
                                                                    +----------------+
                                                                    | one_equals_two |
                                                                    +----------------+
                                                                    | 1 = 2          |
                                                                    +----------------+
                                                                    1 row in set (0.00 sec)
                                                                    

                                                                    и именно из-за этого я не люблю ENUM, но вроде это тоже документировано
                                                                      0
                                                                      Некорректно сравнивать максимум енума(де факто другой формат) с числом.
                                                                        0
                                                                        Странно но официальная документация с вами не согласна
                                                                        Sorting ENUM values are sorted based on their index numbers, which depend on the order in which the enumeration members were listed in the column specification. For example, 'b' sorts before 'a' for ENUM('b', 'a'). The empty string sorts before nonempty strings, and NULL values sort before all other enumeration values. To prevent unexpected results when using the ORDER BY clause on an ENUM column, use one of these techniques: Specify the ENUM list in alphabetic order. Make sure that the column is sorted lexically rather than by index number by coding ORDER BY CAST(col AS CHAR) or ORDER BY CONCAT(col).
                                                                        Т. е. Я так понимаю вас не смущает что максимальный элемент имеет индекс 2 хотя я четко вижу что согласно декларации индекс 2 имеет элемент '0' а никак не '1'? Вы глубже смотрите а не на то как называются поля и таблицы.
                                                                          0
                                                                          А еще раз подумать:
                                                                          Sorting ENUM values are sorted based on their index numbers,
                                                                            +1
                                                                            Давайте я на всякий случай переведу, чтобы исключить разночтения.
                                                                            Сортировка. ENUM значения сортируются на основании их номера индекса

                                                                            Соотвественно было бы разумно ожидать что в перечислении данного типа:
                                                                            enum('1','0')
                                                                            

                                                                            элемент с именем '1' имеет порядковый номер 1, а элемент с именем '0' порядковый номер 2.
                                                                            Тут как бы MySQL с нами полностью согласен:
                                                                            select   number_value, number_value   0
                                                                                from two_numbers
                                                                            order by number_value desc;
                                                                             ------ ------ 
                                                                            | val  | ord  |
                                                                             ------ ------ 
                                                                            | 0    |    2 |
                                                                            | 1    |    1 |
                                                                             ------ ------ 
                                                                            

                                                                            Но вот те кто писал функцию MAX(MIN) об этом видимо не знали, так как
                                                                            select min(number_value) min_val from two_numbers;
                                                                             --------- 
                                                                            | min_val |
                                                                             --------- 
                                                                            | 0       |
                                                                             --------- 
                                                                            1 row in set (0.00 sec)
                                                                            

                                                                            т.е. сравнение производится не согласно индексам, как они заданы при создании, а просто в лексикографическом порядке. При чем первая же арифметическая операция заставляет работать MySQL согласно документации.
                                                                            А еще раз подумать:

                                                                            Я почитал ваши статьи, ряд из них я нашел даже интересными, ибо сам раньше программировал под Oracle, так что действительно — подумайте, вроде статья старая, никто никуда не спешит.
                                                                              –2
                                                                              Если вы программировали под оракл, да и вообще с приведением типов то вы должны понимать, что только приведение типа детерминирует операцию. Именно +0 и делает неявный автокаст.
                                                                                +2
                                                                                При чем тут автокаст? Автокаст — это workaround для этого бага. сортировка все сортирует по индексам и верно, почему максимальных по индексу элемент '1' а не '0'?
                                                                0
                                                                bugs.mysql.com/bug.php?id=66896 — это про первый запрос, DISTINCT + GROUP BY
                                                                  0
                                                                  bugs.mysql.com/bug.php?id=67578 — это про ELT + LEAST

                                                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                  Самое читаемое