Как происходят неявные преобразования в sqlite? - PullRequest
0 голосов
/ 24 марта 2020

В SQLite используется динамическая типизация c и неявные преобразования выполняются в выражениях. Например,

SELECT (3 < 2); -- false
SELECT (3 < '2'); -- true (what's happning here?)
SELECT ('3' < '2'); -- false

SELECT (3 < 20); -- true
SELECT (3 < '20'); -- true (what's happning here?)
SELECT ('3' < '20'); -- false

Но официальная документация и книга O'REILLY Использование SQLite ничего не говорят о как операнды преобразуются в неявные преобразования.

В C ++ Standard строго определяет (то есть явно объясняет), как происходят неявные преобразования. Например, если один из операндов имеет тип long double, другой операнд приводится к long double.

Существует ли такое правило в SQLite?

Ответы [ 2 ]

1 голос
/ 24 марта 2020

Иногда происходят неявные преобразования, но иногда нет. Условия, которые определяют, выполняются ли преобразования перед сравнениями, описаны в 4.2. Преобразования типов до сравнения . Согласно разделу,

Сродство применяется к операндам оператора сравнения перед сравнением в соответствии со следующими правилами в указанном порядке:

  • Если один операнд имеет сходство INTEGER, REAL или NUMERI C, а другой операнд имеет TEXT или BLOB или не имеет сходства, тогда сходство NUMERI C применяется к другому операнду.

  • Если один операнд имеет сходство TEXT, а другой не имеет сходства, тогда сходство TEXT применяется к другому операнду.

  • В противном случае, сходство не применяется, и оба операнда сравниваются как есть.

Но как определяется сходство типов выражения (включая литералы)? Это объясняется в 3.2. Сходство выражений как

Каждый столбец таблицы имеет сходство типов (одно из BLOB, TEXT, INTEGER, REAL или NUMERI C), но выражения не обязательно имеют affinity.

Сходство выражения определяется по следующим правилам:

  • Правый операнд оператора IN или NOT IN не имеет сходства, если операнд является списком и имеет то же сходство, что и сходство выражения набора результатов, если операндом является SELECT.

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

    1. Скобки вокруг имени столбца игнорируются. Следовательно, если X и YZ являются именами столбцов, то (X) и (YZ) также считаются именами столбцов и имеют сходство с соответствующими столбцами.

    2. Любые операторы, применяемые к именам столбцов, включая безоперационный унарный оператор «+», преобразуйте имя столбца в выражение, которое всегда не имеет сходства. Следовательно, даже если X и YZ являются именами столбцов, выражения + X и + YZ не являются именами столбцов и не имеют сходства.

  • Выражение в форме «CAST (expr AS type)» имеет сходство, аналогичное столбцу с объявленным типом «type».

  • Оператор COLLATE имеет то же сходство, что и его левый операнд.

  • В противном случае выражение не имеет сходства.

Так что в случаях примеров в OP литералы не имеют сродства и поэтому сравниваются как есть. Поскольку

Значение INTEGER или REAL меньше, чем любое значение TEXT или BLOB.

, как указано в ответе forpas , 3 < '2' возвращает true.

Эти правила правильно описывают явно странное поведение, упомянутое в этом комментарии . CAST ('1' AS INTEGER) имеет сходство типов INTEGER, поэтому >= '1' интерпретируется как >= 1 и, таким образом, CAST ('1' AS INTEGER) >= '1' возвращает true, тогда как 1 >= '1' возвращает false.

1 голос
/ 24 марта 2020

С Типы данных в SQLite версии 3 / 4.1. Порядок сортировки :

Значение INTEGER или REAL на меньше любого значения TEXT или BLOB.

Очевидно:

SELECT TYPEOF(3);

возвращает integer и

SELECT TYPEOF('2');
SELECT TYPEOF('20');

возвращает text. Таким образом, здесь нет преобразования:

SELECT 3 < '2';

, которое возвращает true. Но есть неявное преобразование в выражении, подобном этому:

SELECT 3 < '2' + 0;

, которое возвращает false, и это преобразование вызывается оператором +, который применяет число c операция в '2', таким образом, преобразовывая его в integer. Изменить, чтобы уточнить: Это поведение применяется только к литеральным значениям, таким как 3 и '2'. Когда речь идет о выражениях или значениях столбцов, происходит неявное преобразование . Поэтому, если вы определите таблицу наподобие:

create table test(id integer); 
insert into test(id) values (1), (2), (3); 

, выражение наподобие:

select * from test where id > '1'

вернет:

| id  |
| --- |
| 2   |
| 3   |

см. demo .

...