使用3个不同的索引选择行范围

时间:2009-09-02 03:18:08

标签: sql mysql

我的数据库如下所示:

Book,Chapter,Verse,Scripture
"1","1","1","1text1"
"1","1","2","1text2"
"1","1","3","1text3"
"1","1","4","1text4"
"1","2","1","2text1"
"1","2","2","2text2"
"1","2","3","2text3"

我想选择1,1,1到1,2,3的所有行。

但是我当前的查询不会返回第1,1,4行,因为4大于3。

SELECT * FROM my_table WHERE 
Book >= 1 AND Book <= 1 AND 
Chapter >= 1 AND Chapter <= 2 AND
Verse >= 1 AND Verse <= 3

5 个答案:

答案 0 :(得分:2)

MySQL也支持row constructors。如果您想要(例如)1 1:3到1 2:2,请使用:

SELECT * FROM bible
    WHERE (1,1,3) <= (book, chapter, verse) AND (book, chapter, verse) <= (1,2,2)

58 1:3到62 4:2,

SELECT * FROM bible
    WHERE (58,1,3) <= (book, chapter, verse) AND (book, chapter, verse) <= (62,4,2)

58 1:4将包括在内,59 1:1和60 10:10,但不包括62 5:1。

我找不到太多文档,但是MySQL遵循自SQL-92以来为行比较设置的行为(注意:链接是草稿版本),特别是第8.2节“一般规则”7):< / p>

  

设R x 和R y 是比较谓词的两个行值构造函数,并且让R x i 和R y i 是R x 和R y 的第i行值构造元素,分别。 “R x [comp op] R y ”为真,假或未知如下:
  [...]
  c)当且仅当R x i = R <时,“R x &lt; R y ”为真对于所有i y i n和R x n &lt;对于某些n,R y n

     

d)当且仅当R x i 时,“R x > R y ”为真所有i <= R y i n和R x n &gt;对于某些n,R y n

     

e)当且仅当R x = R y <时,“R x &lt; = R y ”为真/ sup>或R x &lt; [R ý

     

f)当且仅当R x = R y <时,“R x > = R y ”为真/ sup>或R x &gt; [R ý

第9.2节Joe Celko的SQL For Smarties(链接到第3版,但在早期版本中存在相同的主题)中讨论了行比较。

答案 1 :(得分:1)

数据模型中缺少的是Book,Chapter和verse与层次结构相关的事实。

如果对于每个条目,您还存储了将书章和诗节组合在一起的单个数据项,搜索给定范围只需要一个简单的BETWEEN运算符。

让我们说你知道没有一本书包含超过99章,而且没有章节包含999多节经文。你可以计算(Book * 100 + Chapter)* 1000 + Verse 对于存储的每个项目,并将其存储在单独的列中。 (是的,我知道这是多余的)。

然后你可以在(1 * 100 + 1)* 1000 + 1和(1 * 100 + 2)* 1000 + 5之间搜索该列 找到从1,1,1到1,2,5的所有内容。

答案 2 :(得分:0)

您需要使用OR语句。

SELECT * FROM my_table WHERE 
(Book = 1 AND 
Chapter BETWEEN 1 AND 2
Verse BETWEEN 1 AND 2)
OR
(/* THE OTHER STATEMENT */)
OR
(/* THE OTHER STATEMENT */)

修改

如果您使用BETWEEN运算符

,则更加清晰

答案 3 :(得分:0)

这就是我在书中选择范围时所提出的。 如果我想从1,1,3到1,7,2

SELECT * FROM Bible WHERE Book = 1 AND Chapter = 1 AND Verse >= 3
UNION
SELECT * FROM Bible WHERE Book = 1 AND Chapter >1 AND Chapter <7
UNION
SELECT * FROM Bible WHERE Book = 1 AND Chapter = 7 AND Verse <=2

选择书籍范围:58,1,3到62,4,2

SELECT * FROM Bible WHERE Book = 58 AND Chapter = 1 AND Verse >= 3
UNION
SELECT * FROM Bible WHERE Book = 58 AND Chapter > 1
UNION
SELECT * FROM Bible WHERE Book > 58 AND Book < 62
UNION
SELECT * FROM Bible WHERE Book = 62 AND Chapter < 4
UNION
SELECT * FROM Bible WHERE Book = 62 AND Chapter = 4 AND Verse <=2

答案 4 :(得分:0)

我能想到的唯一解决方案是添加一个额外的索引列:

ALTER TABLE my_table ADD VerseIndex CHAR(10) NOT NULL, INDEX(VerseIndex(4));

UPDATE my_table SET VerseIndex = CONCAT(
                                        LPAD(Book, 2, '0'),
                                        '-', LPAD(Chapter, 3, '0'),
                                        '-', LPAD(Verse, 3, '0')
                                        );

现在,您的表中应该有一个额外的列,文本值为“ - ”,mysql可以按字母顺序搜索,为您提供精确的范围:

# find book 2 chapter 4 v 3 through to book 3 chapter 1 v 1 (inclusive)
SELECT * FROM my_table WHERE VerseIndex BETWEEN '02-004-003' AND '03-001-001' ORDER BY VerseIndex;

# find book 5 chapter 4 (whole chapter) through to book 7 end of chapter 9
SELECT * FROM my_table WHERE VerseIndex BETWEEN '05-004-000' AND '07-009-999' ORDER BY VerseIndex;