Сравнение sqlite кортежей - PullRequest
       22

Сравнение sqlite кортежей

6 голосов
/ 18 апреля 2011

Попытка сделать то же самое, что и этот вопрос , но на этот раз в sqlite.В моем текущем приложении мне нужно иметь возможность выполнить этот тип запроса:

SELECT First, Last, Score
FROM mytable
WHERE
    ('John',  'Jordan',  5) <= (First, Last, Score )
    AND (First, Last, Score) <= ('Mike',  'Taylor',  50) 
ORDER BY First, Last, Score
LIMIT 1

и получить ответ ('Liz', 'Jordan', 2), учитывая эти данные:

+-------+---------+-------+
| First | Last    | Score |
+-------+---------+-------+
| Liz   | Jordan  |     2 |
| John  | Jordan  |     2 |
| Liz   | Lemon   |    10 |
| Mike  | Taylor  |   100 |
| John  | Jackson |  1000 |
| Mike  | Wayne   |     1 |
| Liz   | Lemon   |    20 |
| Liz   | Meyers  |     5 |
| Bruce | Jackson |     1 |
+-------+---------+-------+

Что такоесамый эффективный способ сделать это в sqlite?Пожалуйста, имейте в виду, что это игрушечный пример, и что мое реальное приложение имеет таблицы с большим количеством столбцов и типов данных и сотнями миллионов строк.

Если решение легко расширяется на большее / меньшее количество столбцов,это даже лучше.


Сравнение кортежей:

Кортежи упорядочены лексикографически, что означает, что последовательности упорядочены так же, как их первые отличающиеся элементы.Например, (1,2, x) <(1,2, y) возвращает то же самое, что и x <y.</p>

Стоит отметить, что SQL-92 (и mysql, oracle, postresql) реализуют это правильно.Стандарт использует «конструктор значений строк» ​​для обозначения того, что я называю кортежем.Поведение детально описано в часть 8.2.7, стр. 209 .


Вот необходимый SQL-код для создания примера:

create table mytable ( First char(20), Last char(20), Score int );
insert into mytable values ('Liz', 'Jordan', 2);
insert into mytable values ('John', 'Jordan', 2);
insert into mytable values ('Liz', 'Lemon', 10);
insert into mytable values ('Mike', 'Taylor', 100);
insert into mytable values ('John', 'Jackson', 1000);
insert into mytable values ('Mike', 'Wayne', 1);
insert into mytable values ('Liz', 'Lemon', 20);
insert into mytable values ('Liz', 'Meyers', 5);
insert into mytable values ('Bruce', 'Jackson', 1);
create unique index 'UNIQ' on mytable (First, Last, Score);

Ответы [ 2 ]

6 голосов
/ 27 апреля 2011

SQLite не поддерживает сравнение кортежей. Но конструктор строк - это своего рода сокращение. Вы можете получить тот же результат с более сложным предложением WHERE. Я опустил предложение LIMIT 1, чтобы было легче увидеть, что оба запроса возвращают один и тот же набор. (То есть на платформах, которые поддерживают конструкторы строк.)

Это сравнение

ROW(a,b) <= ROW(c,d) 

эквивалентно

a < c OR (a = c AND b <= d)

И вы можете расширить это количество столбцов, сколько вам нужно.

SELECT First, Last, Score
FROM mytable
WHERE
      (('John' < First) OR 
       ('John' = First AND 'Jordan' < Last) OR 
       ('John' = First AND 'Jordan' = Last AND 5 <= Score))
  AND ((First < 'Mike') OR 
       (First = 'Mike' AND Last < 'Taylor') OR 
       (First = 'Mike' AND Last = 'Taylor' AND Score <= 50))
ORDER BY First, Last, Score

Liz  Jordan  2
Liz  Lemon  10
Liz  Lemon  20
Liz  Meyers  5

Я не проверял это с NULL в данных.


Начиная с 2018 года, SQLite поддерживает сравнение кортежей. Запрос OP производит ожидаемый результат, используя предоставленные операторы SQL. Этот способ написания запроса также работает. (Я нахожу between ... and ... более читабельным.)

SELECT First, Last, Score
FROM mytable
WHERE (First, Last, Score ) between ('John',  'Jordan',  5) and ('Mike',  'Taylor',  50) 
ORDER BY First, Last, Score
Limit 1

Я не знаю, как давно это было введено.

1 голос
/ 29 января 2013

Я обошел отсутствие сравнения кортежей, используя конкатенацию строк (||) и последовательность символов, чтобы гарантировать, что поля не «сливаются» и не приводят к неправильным совпадениям (-).

(First, Last, Score) <= ('Mike',  'Taylor',  50)

становится

First||' - '||Last||' - '||Score <= 'Mike'||' - '||'Taylor'||' - '||'50'

или

First||' - '||Last||' - '||Score <= 'Mike - Taylor - 50'

, поэтому ваш SELECT будет

SELECT First, Last, Score
FROM mytable
WHERE
    'John - Jordan - 5' <= First||' - '||Last||' - '||Score
    AND First||' - '||Last||' - '||Score <= 'Mike - Taylor - 50'
ORDER BY First, Last, Score
LIMIT 1

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

...