Смешивание значений в кавычках и без кавычек в условии IN () - MySQL Причуд или общая проблема? - PullRequest
3 голосов
/ 07 марта 2020

Руководство MySQL содержит следующую интересную заметку о смешивании значений в кавычках и без кавычек в условии IN:

Никогда не следует смешивать значения в кавычках и без кавычек в список IN (), потому что правила сравнения для значений в кавычках (таких как строки) и значений без кавычек (таких как числа) различаются. Поэтому смешивание типов может привести к противоречивым результатам.

Однако это не объясняет, почему это проблема. В нем есть примеры, но он не показывает ни запрашиваемые данные, ни результаты, поэтому они служат только в качестве иллюстраций, не давая никаких объяснений по поводу проблемы.

У меня есть два вопроса:

  1. Почему это вызывает проблемы в MySQL? В идеале приведите пример, где результаты неверны / противоречивы / не интуитивны, чтобы продемонстрировать.
  2. Это MySQL -specifi c Причудка или это относится к другим системам баз данных? В частности, меня интересует, влияет ли эта проблема на SQL Сервер, но в идеале хотелось бы, чтобы вопрос отвечал в общем случае.

Ответы [ 7 ]

0 голосов
/ 17 марта 2020

1. Почему это вызывает проблемы в MySQL?
Механизм должен знать, как он будет выполнять сравнения.
Если вы сравниваете столбец с целыми числами, целочисленное значение столбца будет сравниваться со списком IN. Если элементы списка IN являются строками, сравнение будет другим.
https://dev.mysql.com/doc/refman/8.0/en/type-conversion.html

2. Это MySQL -специфическая c причуда или это относится к другим системам баз данных?
Это не MYSQL специфицируется c. Из соображений производительности (индексация) всегда лучше не делать кастинг.

0 голосов
/ 03 апреля 2020

Несмотря на то, что было получено много ответов и комментариев, содержащих примеры «неинтуитивного» поведения, большинство из этих примеров, по-видимому, объясняются стандартными правилами приведения. Другими словами, результаты полностью соответствовали тому, что будет возвращено из SELECT A = B; для заданных A и B.

«Потому что приведение» не похоже на особенно удовлетворительное объяснение абзаца, который я цитировал в этом вопросе. Этот абзац следует после ряда абзацев, объясняющих, как преобразование типов влияет на оператор IN(), поэтому он выглядит несколько повторяющимся и избыточным, если это все, на что он ссылается.

Моя интерпретация В кавычке говорится, что это явное утверждение, что a IN(b, c) может давать разные результаты для a = b OR a = c в ситуациях, когда b и c цитируются по-разному.

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

Я думаю, что причина того, что мы еще не видели хорошего примера, заключается в том, что большинство ответов сосредоточено на сравнении чисел, в строковых и нестроковых представлениях. Однако, взяв за основу тест на строковых значениях, мне удалось создать неинтуитивный пример, который не объясняется простыми правилами преобразования типов и который не эквивалентен отдельным сравнениям OR, объединенным вместе; сравнение между 'test' и 23 дает разные результаты в зависимости от того, какие другие значения есть в списке IN():

SELECT 'test' IN('fish');       --> 0
SELECT 'test' IN(23);           --> 0
SELECT 'test' IN('fish', 23);   --> 1 !!!

Мне еще предстоит придумать хорошее объяснение того, что здесь происходит - есть ли какое-то правило, которому нужно следовать, или это просто MySQL причуда? У меня также нет ответа на второй вопрос, поскольку это в некоторой степени зависит от причины поведения (например, определяется ли оно стандартом или является артефактом очевидной оптимизации, а не просто MySQL - указать c причуду) но я думаю, что это можно выяснить, запустив вышеуказанный тест на других СУБД.

Любые комментарии, которые помогут вывести sh это (или ответы, которые охватывают отсутствующие элементы) будут признателен - я дополню этот ответ любыми дальнейшими подробностями, которые мне удастся вывести, и не планирую принимать какие-либо ответы (включая мой собственный), пока не пойму, что происходит немного лучше.

0 голосов
/ 16 марта 2020

Почему это вызывает проблемы в MySQL?

Это не ошибка, это особенность. 100

В основном речь идет о том, как база данных обрабатывает сравнение полей. В частности, MySQL автоматически преобразует строковое значение в числовое значение c при сравнении числового значения c со строковыми значениями. Поскольку MySQL - это , написанное на C ++ , где-то в базе кода они должны приводить строковое значение к double до сравнения полей.

В * 1012 нет ничего особенного * пункт, я думаю. В исходном коде MySQL я видел комментарии, подобные этому:

    `WHERE a IN (b, c)` can also be rewritten as `WHERE a = b OR a = c`

Что имеет смысл, и IN (вероятно) трактуется аналогично в базе кода. Итак, на основании этого, если у нас есть, скажем, что-то вроде этого:

... WHERE '04.2' IN ('0', 4.2);

Что означает '04.2' = '0' OR '04.2' = 4.2 и вернет true, потому что в C / C ++:

"04.2" =  "0"  // string value comparison -> false
cast_as_double("04.2") = 4.2 // double value comparison -> true

То же самое относится и к другим случаям, которые разрешаются как истинные, например 42 IN ('0042', 0), '3.00' IN (3, '1'), 0 IN (3, '0.00') и c.

Является ли это MySQL -specifi c причудой или это применимо к другим системам баз данных?

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

0 голосов
/ 14 марта 2020

1. Почему это вызывает проблемы в MySQL?

В приведенном ниже примере должна быть показана несогласованность использования IN в цитируемых (x='1a') и не заключенных в кавычки типах (x=1). Обратите внимание, что для того же значения x = 1, то же выражение IN дает 0 в запросе 1, но дает 1 в запросе 2.

SELECT
  x, x IN ('1b','a1')
FROM
  (
    select '1a' as x
    union all select 1
  ) q1;

SELECT
  x, x IN ('1b','a1')
FROM
  (
    select 1 as x
  ) q1;

Результаты:

Query 1:
'1a': 0
1: 0

Query 2:
1: 1

Для дальнего I не могу наблюдать несогласованность, если я только изменяю список внутри IN. Но я заметил, что шаблон выглядит так:

expr IN (... массив значений)

Для expr со строкой против значений string : сравнить как строка Для expr без строки, против string значения: сравнить как число Для expr со строкой для числовых значений c: сравнить как число Для expr без строки, напротив числовых значений c: сравните как число

2. Это MySQL -специфическая c причуда или это относится к другим системам баз данных?

В каждом конкретном случае. Для MS SQL я говорю вам нет, потому что, сравнивая строку с номером, они выдают сообщение об ошибке вроде: Conversion failed when converting the varchar value '1a' to data type int.

0 голосов
/ 13 марта 2020

При выполнении некоторых простых тестов управление между типами данных выполняется правильно, несмотря на то, что написано в руководстве MySQL.

SELECT 0 IN ('0','00',0,00); -> TRUE
SELECT 0 IN ('0','01',1,01); -> TRUE
SELECT 0 IN ('1','00',1,10); -> TRUE
SELECT 0 IN ('11','10',0,10); -> TRUE
SELECT 0 IN ('1','01',1,00); -> TRUE
SELECT '0' IN ('1','01',1,00); -> TRUE
SELECT '0' IN ('0','00',0,00); -> TRUE
SELECT '0' IN ('0','01',1,01); -> TRUE
SELECT '0' IN ('1','00',1,10); -> FALSE
SELECT '0' IN ('11','10',0,10); -> TRUE
SELECT '1' IN ('11','10',1,10); -> TRUE
SELECT '15.32' IN ('11','10',1,15.32); -> TRUE
SELECT 13.12 IN ('11','10',1,13.12); -> TRUE
SELECT 00 IN ('11','00',1,13.12); -> TRUE
SELECT '00' IN ('11',00,1,13.12); -> TRUE
SELECT '00.0' IN ('11',00.0,1,13.12); -> TRUE
SELECT '00.00' IN ('11',0,1,13.12); -> TRUE
SELECT '00.01' IN ('11',0.01,1,13.12); -> TRUE

Вышеуказанные результаты можно увидеть в этом SQLFiddle

Но вышеприведенные тесты даже не близки к тестированию всех различных типов данных MySQL.

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

MySQL пишет, что смешанные типы данных иногда дают неожиданные результаты, но опять же действительно ли необходимо иметь разные типы данных внутри IN ()?

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

Например, не кажется ли сравнение столбца TEXT с IN ('Hello','World',13) странным? Я знаю, что можно возразить, что в столбце с типом данных TEXT могут быть числовые значения. Хорошо, тогда просто напишите выше, как это IN ('Hello','World','13'), так как мы говорили о столбце TEXT.

В случае, если мы не знаем тип данных или если каким-то образом тип данных является динамическим c и может несколько раз измениться, тогда мы должны преобразовать это поле в тип данных, который мы ожидаем, что большинство результатов будет.

0 голосов
/ 10 марта 2020

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

mysql> SELECT 'a' IN (0), 0 IN ('b');
        -> 1, 1

То, что вы можете расширить:

SELECT 'a' IN (0, 1, '2'), 'a' IN ('0', '1', '2');
-> 1, 0
SELECT 0 IN (0.0, 'b'), 0 IN ('0.0', 'b');
-> 1, 1

Также есть этот другой вопрос :

В MySQL, почему следующий запрос возвращает '----', '0', '000', 'AK3462', 'AL11111', 'C131521', ' TEST ', et c.?

select varCharColumn from myTable where varCharColumn in (-1, '');

Я не получаю ни одного из этих результатов, когда делаю:

select varCharColumn from myTable where varCharColumn in (-1);

select varCharColumn from myTable where varCharColumn in ('');

Все брошено в float, скорее всего, согласно этой ссылке :

[...] Во всех остальных случаях аргументы сравниваются как числа с плавающей точкой (действительные). Например, сравнение строк и чисел c операндов происходит как сравнение чисел с плавающей точкой.

И строки приводятся как 0.0, если они не начинаются с цифр. Кроме того, по той же ссылке могут возникнуть проблемы с точностью с плавающей запятой и запросами, не использующими индекс, потому что тип неправильный (он должен приводить все к плавающему значению, поэтому, я полагаю, нет использования индекса).

Я думаю, что вы могли бы получить что-то похожее, но не то же самое с каждой СУБД, потому что вам нужно приводить вещи, чтобы сравнить их. Это может быть не совсем та же проблема в SQL Server, потому что приоритет типа данных не совпадает, но вы должны сравнить данные одного и того же типа данных. По этой ссылке, которая дает приоритет типа данных для SQL Сервер :

  1. пользовательские типы данных (максимальный)
  2. sql_variant
  3. xml
  4. datetimeoffset
  5. datetime2
  6. datetime
  7. smalldatetime
  8. date
  9. time
  10. float
  11. real
  12. десятичное число
  13. деньги
  14. smallmoney
  15. bigint
  16. int
  17. smallint
  18. tinyint
  19. бит
  20. ntext
  21. текст
  22. изображение
  23. метка времени
  24. uniqueidentifier
  25. nvarchar (включая nvarchar (max))
  26. nchar
  27. varchar (включая varchar (max))
  28. char
  29. varbinary (включая varbinary (max))
  30. двоичный (самый низкий)

int и строка будет приведена к типу int (не с плавающей точкой) для сервера SQL СУБД.

0 голосов
/ 07 марта 2020

Это зависит от того, что вы считаете «неинтуитивным». Возвращает false:

'00' in ('0', '01')

Однако возвращает true:

'00' in (0, '01')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...