6

尝试做与这个问题相同的事情,但这次是在 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 相同。

值得注意的是,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);
4

2 回答 2

7

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

我不知道这是多久以前介绍的。

于 2011-04-26T22:42:45.563 回答
1

我一直在通过使用字符串连接 ( ||) 和字符序列来避免缺少元组比较,以确保字段不会“合并”并导致不正确的匹配 ( -)。

(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

字符串连接非常昂贵且不那么简洁,但它的工作方式相同并且看起来非常相似。

于 2013-01-29T16:33:09.010 回答