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 に答える