Comments 125
Если этот комментарий наберет 200 плюсов я станцую ганнам на красной площади. С наступающим
Если честно, хотелось бы чуть более разжеванных примеров.
И так вопрос, какой знак имеет число 0. Не торопитесь с ответом, вы же уже поняли, что разработчики MySQL жуткие тролли.
Это не разработчики MySQL тролли, а разработчики стандарта IEEE 754: en.wikipedia.org/wiki/Signed_zero
Результат ROUND(-0.1) в MySQL — это фактически значение, которое возвращает glibc-шная функция rint(-0.1). Которая действительно возвращает ноль со знаком минус.
Это не разработчики MySQL тролли, а разработчики стандарта IEEE 754: en.wikipedia.org/wiki/Signed_zero
Результат ROUND(-0.1) в MySQL — это фактически значение, которое возвращает glibc-шная функция rint(-0.1). Которая действительно возвращает ноль со знаком минус.
Спасибо за информацию, но -0=+0=0 значит лишних кортежей при группировке возникать не должно.
Нет, +0 и -0 это разное. По крайней мере на один бит точно должны отличаться, сейчас посмотрю IEEE 754…
Угу это и приходится объяснять бизнесу когда у них в отчетах 2 строки 0 с разным тоталом :) вы не про стандарт думайте а про конечного пользователя.
Лучше себе объясните зачем вы для денежных вычислений используете числа с плавающей точкой.
Можете составить такой же пример с целыми числами поделив их. Такой же результат должен быть, к сожалению не могу проверить уже. Float в примере просто для простоты восприятия.
Для дробной части суммы?
хранить в неделимых еденицах? копейки, центы и т.д.
Судя по количеству плюсов комментария выше я, вероятно, чего-то не знаю или не понимаю. Объясните кто-нибудь, пожалуйста, почему нельзя использовать естественное представление данных с дробной частью? Зачем разносить на две колонки целая-дробная часть?
Кто говорит про разнесение? Одна колонка. Целочисленная. Нужно сохранить $120.99, записываем — 12099.
Хорошо, пусть так. Но зачем?
меньше потерь в математических операциях. www.databasesandlife.com/store-currency-amounts-as-number-of-cents-pence-etc/
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)
Стоит заметить, что почти во всех ЯП есть типы для точной работы с floating point числами, но это естественно медленнее чем работа с целыми числами.
Примеры в студию — желательно тупейшие. Можно и те и те.
Примеры скорости или типов данных?
А мне типов, я не знаю как можно работать с floating point точно.
В пхп не скажу. Но в 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
еще в руби есть тип Rational и библиотека mathn.
Работает странно, но точно :)
1.9.3p327 :021 > Rational(0.55)
=> (2476979795053773/4503599627370496)
Работает странно, но точно :)
Оно работает из-за округления, и можно получить такие же погрешности:
BigDecimal.new(1, 2) - BigDecimal.new(0.7, 2) == BigDecimal.new(0.2999, 2) # true
ну вы же должны расчитывать с какой точностью будете работать. если это деньги, то берем точность 6 и все.
В php нету из коробки, но можно заюзать java`вскую через extension кастомный.
Ruby
Как видите почти в 6 раз медленнее
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 раз медленнее
Однострочники:
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 то минус есть или наоборот — 0 то +
-0 равен 0 судя из примера: группировка была по -0 и 0 т.к. в поле group_concat видим все 2 значения, значит они равны. Или я что то просмотрел?
Согласен, лишних кортежей быть не должно. Как выяснилось, это проблема HASH индексов в MEMORY storage engine: bugs.mysql.com/bug.php?id=67978
А что документация говорит по этому поводу?
Или на такой пример:
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)
И первый и второй случай это стандартное поведение если не указывать дополнительных режимов работы БД. Посмотрите SQL_MODE.
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)
Не поскажете какой параметр фиксит это?
Да вы правы ERROR_FOR_DIVISION_BY_ZERO на который я рассчитывал фиксит это только для DML операций согласно документации. Но опять же согласно ей же это поведение для мускуля нормально. Просто надо к нему привыкнуть и при необходимости ставить coalesce. Так же думаю надо проверить как это работает в процедурах. Там же ест обработчик деления на ноль. Он должен перехватить. Но согласитесь то о чем вы написали все знают как хорошо документированную фичу.
Помимо документации, есть еще стандарт ANSI SQL, и он должен быть главнее документации по БД. По поводу деления на ноль, стандарт прямо говорит, что должен происходить Exception.
«If the value of a divisor is zero, then an exception condition is raised: data exception-division by zero.»
«If the value of a divisor is zero, then an exception condition is raised: data exception-division by zero.»
А что есть «an exception condition»?
Когда я забываю указать поля вставки в insert или допускаю в своем коде деление на ноль, мне некого ругать кроме самого себя. А вот когда выясняется, что null is not null это уже из другой области.
где то читал, что null это неопределенное значение и следовательно ни себе не равно и чему другому. И результат деления на 0 = неопределённое число… получается логично.
В математике, если уже и делится на 0, то получается определенная величина тоже — бесконечность.
Так что логики пока не видно.
1.0 / 0.0 => Infinity
Так что логики пока не видно.
Да вы что… а я всегда думал что в стандартной арифметике «Результат деления на ноль не определен». А за «бесконечность — определённая величина» вам 2 и на повторный курс 8-го класса…
Операции деления ненулевого числа на ноль не соответствует никакое действительное число.
Результат этой операции считается бесконечно большим и равным бесконечности: bit.ly/gpa8nr
Значение операции 0:0 (ноль деленное на ноль) неопределенно (которое я и не рассматривал).
> 0.0 / 0.0
=> NaN
> 1.0 / 0.0
=> Infinity
Результат этой операции считается бесконечно большим и равным бесконечности: bit.ly/gpa8nr
Значение операции 0:0 (ноль деленное на ноль) неопределенно (которое я и не рассматривал).
> 0.0 / 0.0
=> NaN
> 1.0 / 0.0
=> Infinity
ну уж 65535 десятичных цифр — нам точно хватит
Совсем не так. Знаковый bigint хранит значения от -9223372036854775808 до 9223372036854775807, т.е. 19 знаков. Что немного меньше, чем 65535,
Ну я как бы об этом и писал. Вы запрос ты выполнить не поленитесь. А потом посмотрите структуры созданной таблицы. И подумайте что будет при восстановлении БД из бэкапа или репликации.
Я не совсем понимаю, о чём вы говорите. Цифра в скобках (65535) вообще к диапазону хранимых значений никакого отношения не имеет. От того, что вы укажете там 1 или 42 — данные не изменятся абсолютно никак.
А то что cast( as signed integer) на выходе дает mediumtext тоже не о чем не говорит? Конечно вы не сможете записать туда такие значения и сделать вид что это bigint.
Я повторю ещё раз — вы как минимум вводите в заблуждение читателей, как максимум — заблуждаетесь сами, считая, что число 65535 имеет хоть какое-то влияние на хранимые данные.
Вы вообще о чем?
Я прошу БД сделать мне bigint из строки длиной 10!
substr(repeat(' ', 21848), 10)
А что получаю в итоге? А то что я пишу что null равно 0 или любой другой пример вас не насторожило что ли?
Я прошу БД сделать мне bigint из строки длиной 10!
substr(repeat(' ', 21848), 10)
А что получаю в итоге? А то что я пишу что null равно 0 или любой другой пример вас не насторожило что ли?
Я о ваших фразах:
> что ж выясним сколько знаков у нас есть
+
> ну уж 65535 десятичных цифр — нам точно хватит
Число знаков, которые позволяет сохранить тип определяется сугубо названием типа, а не числом в скобочках.
Про остальные примеры я не говорю, я с самого начала и до сих пор говорю о вашей единственной некорректной фразе.
> что ж выясним сколько знаков у нас есть
+
> ну уж 65535 десятичных цифр — нам точно хватит
Число знаков, которые позволяет сохранить тип определяется сугубо названием типа, а не числом в скобочках.
Про остальные примеры я не говорю, я с самого начала и до сих пор говорю о вашей единственной некорректной фразе.
А по моему все выводы в этой статье некорректны это же сарказм… Вся статья. Я не пояснил истинные причины ни по одному из примеров. Тут истина только то что mysql выдает кучу не документированного бреда в самый не подходящий момент. И именно это и есть зло.
В случае с bigint(65535) этот «бред» документирован.
dev.mysql.com/doc/refman/5.5/en/numeric-type-attributes.html
dev.mysql.com/doc/refman/5.5/en/numeric-type-attributes.html
С чего вы взяли?
После данного запроса ваша реплика вылетит а дамп придется чистить руками ибо:
а в моей БД такие таблицы бывают ;)
После данного запроса ваша реплика вылетит а дамп придется чистить руками ибо:
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)
О боже.
Я повторю в третий раз: я не спорю, что дамп получится кривой, я лишь говорю, что
> ну уж 65535 десятичных цифр — нам точно хватит
некорректно в принципе, даже в ироничной статье. В особенности после «Ведь все знают что bigint не ограничивается лишь 20 знаками. Как вы не знали? ну что ж это тоже легко доказать.»
Это не доказательство, а введение в заблуждение читателя (который не знает синтаксиса).
Я повторю в третий раз: я не спорю, что дамп получится кривой, я лишь говорю, что
> ну уж 65535 десятичных цифр — нам точно хватит
некорректно в принципе, даже в ироничной статье. В особенности после «Ведь все знают что bigint не ограничивается лишь 20 знаками. Как вы не знали? ну что ж это тоже легко доказать.»
Это не доказательство, а введение в заблуждение читателя (который не знает синтаксиса).
«Недокументированный бред» — это всегда баги. Не стесняйтесь их репортить «своему MySQL вендору».
В MySQL нет таких извращений как в Oracle (там NULL равен пустой строке)
А по-моему это классно. Когда первый раз, ещё в школьные или около того годы, прочитал — тоже подумал: «как это так? А как мне хранить пустые строки? Ну и извращение этот ваш Оракл...» А со временем я понял, что ни разу в жизни мне не попадалась ситуация, где хранение в БД пустой строки имело бы физический смысл. Если пользователь не заполнил необязательное поле формы, или ввёл что-то, а потом удалил — значит по данному полю нет данных, т.е. логически null. Если возникает ситуация, когда по этому полю «сказать нечего», а колонка в базе обозначена NOT NULL — значит имеет место ошибка проектирования. А микс означающих на деле одно и то же «нулей», пустых строк и серий пробелов в одной колонке — вот это извращение. В результате я пришёл к тому, что всегда (разумеется, если бы попался осмысленный повод, я сделал бы исключение) на уровне прослоечного кода делаю сначала trim строки по бокам и если получаю пустую строку, то в базу пишу NULL (а если не пустую — то её (обтримленную)).
А мне как-то не по себе. NULL не д.б. FALSE`ом.
Также NULL не д.б. пустотой — это просто ничто.
NULL — это когда мы не знаем чего-то, а пустая строка — это мы уже знаем, что чего-то нет.
Кароче это всё равно не хорошо так — как-то не по себе что ли.
Также NULL не д.б. пустотой — это просто ничто.
NULL — это когда мы не знаем чего-то, а пустая строка — это мы уже знаем, что чего-то нет.
Кароче это всё равно не хорошо так — как-то не по себе что ли.
В оракле null не является тождественным булеву false. Ну и как по мне вполне логично, что пустота — это ничто.
Все ваши ощущения исключительно от субъективного восприятия NULL. Для меня лично непонятно «NULL — это когда мы не знаем чего-то». Наоборот известно, что нет ничего.
Все ваши ощущения исключительно от субъективного восприятия NULL. Для меня лично непонятно «NULL — это когда мы не знаем чего-то». Наоборот известно, что нет ничего.
Да не совсем. NULL — это когда неизвестно. Нет ничего — это как раз пустая строка или FALSE.
Пример:
Name: Саша
Sex: NULL
Какого пола у нас Саша?
Или другой вариант поля — IsMale
ps: Ежу ясно, что так не делают, но это конно-вакуумно абстракция.
Пример:
Name: Саша
Sex: NULL
Какого пола у нас Саша?
Или другой вариант поля — IsMale
ps: Ежу ясно, что так не делают, но это конно-вакуумно абстракция.
Если Саша не указал/указала пол, то что там кроме нулла должно быть?
Если у вас поле предполагает булево значение, но допускает нулл, ну извиняйте, имхо, небольшая кривизна в моделировании.
И откуда такая уверенность, что False = Null? False — ложное утверждение, null — отсутствие утверждения (вполне коррелирует с пустой строкой).
Если у вас поле предполагает булево значение, но допускает нулл, ну извиняйте, имхо, небольшая кривизна в моделировании.
И откуда такая уверенность, что False = Null? False — ложное утверждение, null — отсутствие утверждения (вполне коррелирует с пустой строкой).
Вообще говоря многозначность значения 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.
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.
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.
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.
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.
И снова о вечной проблеме отсутствующей информации
Сергей Кузнецов
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.
И снова о вечной проблеме отсутствующей информации
Сергей Кузнецов
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?
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?
Это логика такая двоичная. Была бы троичная, было бы как вам хочется.
А я думал мне одному кажется что это не фичи а баги
Начали за здравие, кончили за упокой. Как раз ваша статья подтверждение, что MySQL это плохо:) Это круто, что на 22533 странице документации есть описание того, что константа TRUE = 0, а FALSE =1, но есть еще такая штука, как ожидаемое поведение. Во многих случаях MySQL ведет себя непредсказуемо, притом не очевидно непредсказуемо(хоть с тем же делением на ноль), и требуется долго локализовывать причину и искать в доках причину.
Не скажу, что MySQL плохая, но лично я ее жутко не люблю, т.к. проблем с ней у меня возникало предостаточно, притом неочевидных. Сам предпочитаю postgresql.
Не скажу, что MySQL плохая, но лично я ее жутко не люблю, т.к. проблем с ней у меня возникало предостаточно, притом неочевидных. Сам предпочитаю postgresql.
Утверждение «в Oracle NULL равен пустой строке» не совсем верно. Пустая строка равна NULL, и то по определению, а не по операции сравнения. Любое же сравнение с NULL имеет результатом NULL. То есть не true или false. И это хорошо.
Опять не соглашусь — даже 0 не равен NULL.
NULL — это неизвестность, а ноль — это конкретное количество.
— Сколько вешать в граммах?
— Да х.з. vs. — Ноль грамм.
NULL — это неизвестность, а ноль — это конкретное количество.
— Сколько вешать в граммах?
— Да х.з. vs. — Ноль грамм.
Я упоминал ноль? Надо же.
Да нееет :)) Пустая строка и NULL тоже самое.
Пример:
1. Мы пришли и спросили у продавца: «Сколько стоят вот эти конфеты?» Он нам ответил: «0 руб. — они списаны».
VS
2. Мы пришли и спросили у продавца: «Сколько стоят вот эти конфеты?» Он нам ответил: «Ой, я не знаю — я тут первый день!»
Поэтому «НЕ ЗНАЮ» у нас в итоге не есть «НОЛЬ».
ps: простите за кэпс
pps: упс., опять пример про ноль — в первом варианте было «Как тебя зовут?»
ppppps: Короче это очень тонкое различие, которое не сразу осознаётся. Да и больше оно академично, нежели практично.
Пример:
1. Мы пришли и спросили у продавца: «Сколько стоят вот эти конфеты?» Он нам ответил: «0 руб. — они списаны».
VS
2. Мы пришли и спросили у продавца: «Сколько стоят вот эти конфеты?» Он нам ответил: «Ой, я не знаю — я тут первый день!»
Поэтому «НЕ ЗНАЮ» у нас в итоге не есть «НОЛЬ».
ps: простите за кэпс
pps: упс., опять пример про ноль — в первом варианте было «Как тебя зовут?»
ppppps: Короче это очень тонкое различие, которое не сразу осознаётся. Да и больше оно академично, нежели практично.
Молодой человек, вы приписываете мне то, что я не говорил, и наоборот, лишаете того, что я сказал.
На самом деле даже я допустил неточность в первом комментарии, а именно — все верно лишь для строк типа varchar2 или sql-машины. В pl\sql машине есть нюанс:
На самом деле даже я допустил неточность в первом комментарии, а именно — все верно лишь для строк типа 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;
/
Эхх… Уважаемый товарищ,
Мне до конкретики в конкретной реализации мало интересно доходить.
Я пытаюсь объяснить что такое NULL вообще, а не только в оракле. Если мы друг-друга не поняли, то и хрен с ним тогда.
Вообще в любой системе хранения данных NULL не должен быть равен пустой строке — это моё личное мнение и не утверждение про DBMS IKS.
Мне до конкретики в конкретной реализации мало интересно доходить.
Я пытаюсь объяснить что такое NULL вообще, а не только в оракле. Если мы друг-друга не поняли, то и хрен с ним тогда.
Вообще в любой системе хранения данных NULL не должен быть равен пустой строке — это моё личное мнение и не утверждение про DBMS IKS.
Строго говоря, пример неудачный, т.к. в 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;
/
Уважаю MySQL, только он умеет троллить в ответ на попытки его затроллить.
Я кстати совсем недавно ввел вопрос, где мне нужно было явно узнать количество дней прошеших с начало нового времени и TO_DAYS как ни странно — вернул неправильный результат.
habrahabr.ru/qa/31239/
habrahabr.ru/qa/31239/
Я такого запроса категорически не понимаю! Что за группировка по второму полю, а дистинкт без агрегата по первому?select distinct int_value from null_equals_zero group by group_value;
Как вы понимаете данный запрос вернет нам уникальные значения первой колонки которых как мы знаем два: ноль и NULL
Вывести все уникальные значения для каждой группы.
А если подумать?
Если и подумать не помогло:
«Доказательство», что 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)
Думаю этот ответ стоит откомментировать, ибо в вашей логиге заблуждение как раз из первой группы, так как вы думаете, что группировка в 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 |
+-----------+
и обязательно посмотрите, что будет если группировка делается по одному полю, а выбирается другое.
Еще раз хорошенько подумайте… Нет у вас тут никакой группировки! У вас нет аггрегата! Вы используете исключительно кривой запрос с багом.
Вас не смутило даже то что при изменении порядка вставки элементов поменялся результат запроса?
А вас не смущает писать идиотские невалидные запросы? причем внимательно посмотрите на то, что сами написали:
Как вы понимаете данный запрос вернет нам уникальные значения первой колонки которых как мы знаем два: ноль и NULL
Очень даль что вы считаете меня идотом, а мой пост "имбанутым гавном", о чем вы почему-то не постеснялись написать в твиттере, но постеснялись сказать мне лично в комментариях в этом топике, но я считаю кокретно с вашим вопросом надо разобраться. Новый год все таки. Надо быть позитивнее :)
В отличии от Oracle, в котором вы видимо привыкли работать, MySQL допускает ряд фривольностей в написании group by запросов. К примеру если выбрать поля, по которым не произведена группировка, то MySQL возьмет для значения этого поля — первое попавшееся ему значение в таблице. Т.е. тот результат примера, который вы привели далее немного подумав — вполне ожидаем. Вы произвели группировку по полю с единственным значением, а выбрали поле, по которому группировка не производилась. Собственно MySQL взял первое что ему попалось и вывел в результируещем resultset'е. Я же делаю немного другое. Я провожу группировку по полу в котором 4 значения. Так что у меня получается 4 кортежа. Далее я просто выбираю уникальные поля из всего того что у меня получилось, опуская собственно поля группировки. Воспроизведем эти шаги на значения отличных от NULL.
теперь же попробуем пример из статьи
Я рискну предположить, что тут дело в оптимизаторе, который умеет оптимизировать конструкции типа group by если так же в условии встречается distinct или же limit (с ним тоже есть немало интересных багов, но они сложнее в понимании по этому я их тут не стал приводить, а привел только те, что можно быстро понять).
Если вам непонятет синтаксис, не стоит говорить что это идиотский запрос, ибо парсер отлично этот запрос отработал и даже вернул результат, что уже говорит о том, что запрос написан верно. Стоит все таки действительно немного подумать.
З.Ы. а по поводу неверной оценки статей я с вами частично согласен, ибо на хабре действительно есть множество интересных, по моему мнению технических статей, которые были недостаточно оценены сообществом, но только в этом…
Я такого запроса категорически не понимаю! Что за группировка по второму полю, а дистинкт без агрегата по первому?
В отличии от 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)
теперь же попробуем пример из статьи
получим только одно значение
то, что лежит в БД первее 0 или NULL, но не оба значения сразу, что доказывает предыдущий мой пример из комментария.
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 (с ним тоже есть немало интересных багов, но они сложнее в понимании по этому я их тут не стал приводить, а привел только те, что можно быстро понять).
Если вам непонятет синтаксис, не стоит говорить что это идиотский запрос, ибо парсер отлично этот запрос отработал и даже вернул результат, что уже говорит о том, что запрос написан верно. Стоит все таки действительно немного подумать.
З.Ы. а по поводу неверной оценки статей я с вами частично согласен, ибо на хабре действительно есть множество интересных, по моему мнению технических статей, которые были недостаточно оценены сообществом, но только в этом…
Как меня поражает все-таки наглая попытка увильнут и как-то откреститься от своих же слов и действий. Внимательно смотрите что я процитировал в исходном комменте.
Пройдемся спокойно по списочку:
1. Вы пишете кривой недокументированный запрос
2. Снабжаете его неверной интерпретацией
3. Получаете кривые данные кривого запроса
4. Пытаетесь сделать из этих данных какой-то совершено не взаимосвязанный вывод.
5. В выводе косвенно заявляете о том, что все написанное выше это ошибки разработчиков mysql, но не уточняете, что как минимум этот ваш запрос — это именно ваша ошибка.
Я несколько раз пытался намекнуть, а после уже прямым текстом сказал, что запрос вы пишете невалидный. Багом является то, что не выдает ошибки при запросе об отстутствии агрегата. Не пытайтесь анализировать на невалидных запросах, что вы постоянно пытаетесь делать как и в случаете с enum.
Пройдемся спокойно по списочку:
1. Вы пишете кривой недокументированный запрос
2. Снабжаете его неверной интерпретацией
3. Получаете кривые данные кривого запроса
4. Пытаетесь сделать из этих данных какой-то совершено не взаимосвязанный вывод.
5. В выводе косвенно заявляете о том, что все написанное выше это ошибки разработчиков mysql, но не уточняете, что как минимум этот ваш запрос — это именно ваша ошибка.
Я несколько раз пытался намекнуть, а после уже прямым текстом сказал, что запрос вы пишете невалидный. Багом является то, что не выдает ошибки при запросе об отстутствии агрегата. Не пытайтесь анализировать на невалидных запросах, что вы постоянно пытаетесь делать как и в случаете с enum.
1. запрос не кривой, он успешно работает, и даже всегда за исключением одного случая, возвращает корректные данные.
2. интерпретация запросов неверна в каждом из моих комментариев, но SQL не врет ибо в данном конкретном случае NULL действительно неотличим от 0
3. см 2 пункт выше и пример с 0 и 1, чем они кривой?
4. во всей стаье выводы совершенно бредовые, неужели вы этого не заметили?
5. все это является багами MySQL если вы захотите вы даже сможете найти их номера. Когда я получал данные ошибки я сознательно не заводил баги, ибо пробежавшись по bugs.mysql.com находил очень похожие. Все эти баги не решены до сих пор. Если хотите можете поискать, вон выше сам разработчик MySQL как раз завел новый баг на основании нашего обсуждения этих фич. Вот он bugs.mysql.com/bug.php?id=67978. И поверьте каждый описанный случай основан именно на баге. Конечно сами запросы в которых они возникли гораздо сложнее, но для статьи я переделал их, для того чтобы максимально упростить.
2. интерпретация запросов неверна в каждом из моих комментариев, но SQL не врет ибо в данном конкретном случае NULL действительно неотличим от 0
3. см 2 пункт выше и пример с 0 и 1, чем они кривой?
4. во всей стаье выводы совершенно бредовые, неужели вы этого не заметили?
5. все это является багами MySQL если вы захотите вы даже сможете найти их номера. Когда я получал данные ошибки я сознательно не заводил баги, ибо пробежавшись по bugs.mysql.com находил очень похожие. Все эти баги не решены до сих пор. Если хотите можете поискать, вон выше сам разработчик MySQL как раз завел новый баг на основании нашего обсуждения этих фич. Вот он bugs.mysql.com/bug.php?id=67978. И поверьте каждый описанный случай основан именно на баге. Конечно сами запросы в которых они возникли гораздо сложнее, но для статьи я переделал их, для того чтобы максимально упростить.
Чтобы не продолжать бессмысленный диспут, приведите пруф на документацию, где описано поведение при указании поля вне агрегатов в группировках
А внимательнее? Где там детерминировано поведение дистинкта с этим расширенным поведением? Вот сортировка описана, а дистинкт? То есть вы успешно нашли способ стрельнуть себе в ногу, поздравляю!
Э… Там как бы и про лимит не написано, и про остальные сотню комманд которые там можно впихнуть тоже не слова.
Подумайте: почему при любых значениях кроме NULL и 0 этот запрос работает верно? Вот вы упрямы. Вы свои ошибки в сужениях никогда не признаете?
Заметьте, чуть выше один комментатор написал про bigint, и после длительных баталий в личке, я наконец-то понял что он имеет ввиду, и что это действительно может запутять неопытного читателя, и убрал указанный им пунк. Вы же упрямо не хоите верить ни одному запросу, который я привожу вам в качестве аргументации.
Вы даже не знали про cинтаксис комманды group by! И упорно настаиваете на том, что вы правы, делая это самым хамским образом у всех за спиной… Не надо путать и оскорблять ни меня ни читателя, пожалуйста.
Подумайте: почему при любых значениях кроме NULL и 0 этот запрос работает верно? Вот вы упрямы. Вы свои ошибки в сужениях никогда не признаете?
Заметьте, чуть выше один комментатор написал про bigint, и после длительных баталий в личке, я наконец-то понял что он имеет ввиду, и что это действительно может запутять неопытного читателя, и убрал указанный им пунк. Вы же упрямо не хоите верить ни одному запросу, который я привожу вам в качестве аргументации.
Вы даже не знали про cинтаксис комманды group by! И упорно настаиваете на том, что вы правы, делая это самым хамским образом у всех за спиной… Не надо путать и оскорблять ни меня ни читателя, пожалуйста.
Во-первых, раз используете расширение с нестандартным поведением да еще и прямо противоречащим ansi-стандарту, то должны отталкиваться от документации. Во-вторых, один из известных и применяемых в разных субд алгоритмов дистинкта — это сортировка либо значений/хэшей, что должно было вселить сомнения в валидности.
За спиной? Имхо вполне себе публично, только вот перевирать мои слова не надо.
За спиной? Имхо вполне себе публично, только вот перевирать мои слова не надо.
Вы используете исключительно кривой запрос с багом.
Странно я вроде так и писал в своей статье, очень жаль что вы приняли все за чистую монету. Конечно баги на то и баги, что не везде встречаются. Я просто сделал подборку из тех багов с которыми пришлось столкнуться на протяжении последних трех лет работы…
уберите в запросе дистинкт-может быть это вас натолкнет на верный путь. хотя вам проще почитать про стандарт сиквела
Немного помогу в споре. Запрос:
изначально некорректный, но отрабатывается из-за специфических особенностей MySQL. Вот так можно проверить валидность запроса:
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
И ещё, то что один равно двум доказывается несколько иным способом.
Как-то так
и именно из-за этого я не люблю ENUM, но вроде это тоже документировано
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, но вроде это тоже документировано
Некорректно сравнивать максимум енума(де факто другой формат) с числом.
Странно но официальная документация с вами не согласна
Т. е. Я так понимаю вас не смущает что максимальный элемент имеет индекс 2 хотя я четко вижу что согласно декларации индекс 2 имеет элемент '0' а никак не '1'? Вы глубже смотрите а не на то как называются поля и таблицы.
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'? Вы глубже смотрите а не на то как называются поля и таблицы.
А еще раз подумать:
Sorting ENUM values are sorted based on their index numbers,
Давайте я на всякий случай переведу, чтобы исключить разночтения.
Соотвественно было бы разумно ожидать что в перечислении данного типа:
элемент с именем '1' имеет порядковый номер 1, а элемент с именем '0' порядковый номер 2.
Тут как бы MySQL с нами полностью согласен:
Но вот те кто писал функцию MAX(MIN) об этом видимо не знали, так как
т.е. сравнение производится не согласно индексам, как они заданы при создании, а просто в лексикографическом порядке. При чем первая же арифметическая операция заставляет работать MySQL согласно документации.
Я почитал ваши статьи, ряд из них я нашел даже интересными, ибо сам раньше программировал под Oracle, так что действительно — подумайте, вроде статья старая, никто никуда не спешит.
Сортировка. 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, так что действительно — подумайте, вроде статья старая, никто никуда не спешит.
Если вы программировали под оракл, да и вообще с приведением типов то вы должны понимать, что только приведение типа детерминирует операцию. Именно +0 и делает неявный автокаст.
bugs.mysql.com/bug.php?id=66896 — это про первый запрос, DISTINCT + GROUP BY
bugs.mysql.com/bug.php?id=67578 — это про ELT + LEAST
Sign up to leave a comment.
MySQL: разрушаем стереотипы