最小値を持つすべての行を選択します


9

Sqlite 3では、最小値に基づいて行を選択する方法を理解しようとしています。Googleを効果的に検索するのに十分な関連用語がわからないため、制限があると思います。

テーブルは次のようになります。

num         text        num2      
----------  ----------  ----------
0           a           1         
0           a           2         
1           a           3         
1           b           4         

私は、行を取得したいnum2ですが1, 2、と4。テキスト列の一意の値ごとに、numの最小値に基づいて選択を行います。

だから、のためtext = 'a'の最小値、numである0私は、行1および2.たいのでtext = 'b'、の最小値numであるが1、私は行をしたいので4

することにより、グループの様々な組み合わせを使用して、私はどちらかの行を取得することができるよ12または行を1して4。自分のやりたいことを実行するSQLコンポーネントが不足しているように感じますが、それが何であるかを理解することができませんでした。

このタイプのクエリを実行する適切な方法は何ですか?

可能な解決策

これを行う方法を見つけまし。自分の質問に答えるほど評判がよくないので、ここで更新を行っています。それが常に正しいのか、それとも効率がどの程度なのかはわかりません。コメントは大歓迎です。

1つのクエリでテキストの一意の値ごとにnumの最小値を見つける、複合selectステートメントを使用しました。

sqlite> select num, text from t group by text having num = min( num );
num         text      
----------  ----------
0           a         
1           b         

次に、これをテーブル全体と結合して、これら2つの列に一致するすべての行を取得します。

sqlite> with u as
      ( select num, text from t group by text having num = min( num ) )
        select t.* from t join u on t.num = u.num and t.text = u.text;
num         text        num2      
----------  ----------  ----------
0           a           1         
0           a           2         
1           b           4         

回答:


10

ご覧のとおり、単純なGROUP BYは機能しません。グループごとに1つのレコードしか返されないためです。

結合は正常に機能します。大きなテーブルの場合、結合列(numおよびtext)にインデックスがある場合にのみ効率的です。

または、相関サブクエリを使用することもできます。

SELECT *
FROM t
WHERE num = (SELECT MIN(num)
             FROM t AS t2
             WHERE t2.text = t.text);

SQLFiddle

このクエリは実行時に一時テーブルを必要としません(クエリはの結果に対して実行されますu)が、の各レコードに対してサブクエリを実行するため、インデックスを作成tするtext必要があります。(または両方textでインデックスを使用numして、カバーするインデックスを取得します。)


彼のクエリには一時テーブルがなく、CTEのみがあり、かなり異なります。
ypercubeᵀᴹ

実行すると、uクエリの結果は、CTE、ビュー、またはインラインのいずれでサブクエリとして記述されているかに関係なく、一時テーブルに格納されます。
CL。

おかげで、このバージョンは私が偶然見つけたバージョンよりもはるかに簡単に書くことができます。適切な用語を知ることも、これをさらに詳しく調べるのに役立ちます。
user35292 2014年

@CLこれは、SQLiteがCTEを使用してクエリを実行する方法ですか?そのためのリファレンスはありますか?他のDBMSはctesに一時テーブルを必ずしも使用しないからです。
ypercubeᵀᴹ

@ypercube CTE、ビュー、およびサブクエリは、可能であればフラット化またはコルーチンとして実装されます。ただし、インデックス付けされていない列のGROUP BYは、すべてのグループのデータを並行して収集できる必要があるため、何らかの形式の一時テーブル(すべてのデータベース内)が必要です。
CL。

1

私は外部自己結合でこのタイプのことをする傾向があります:

SELECT
    M1.Num,
    M1.Text,
    M1.Num2
FROM
    MyDb M1
LEFT OUTER JOIN
    MyDB M2
ON
    M1.text = M2.text
AND
    M1.num > m2.num
WHERE
    M2.num is null

これは基本的に言っています。より高い値、つまりnullを持たないすべてのレコードを取得してください。


1

では、次回、自分で質問の答えを自分で見つけるにはどうすればよいでしょうか。私の意見では、それは論理を分解し、それに従うことによるものです。そしてあなたはそれを正しく理解しました:

テキスト列の一意の値ごとにnumの最小値に基づいて選択を行いたい

これは次のように変換されます。

select text, min(num) from t group by text;

(これはhavingクエリと同等でなければなりません。NULLにnum等しい行を確認するのは興味深いかもしれません。より正確には、nullを含む行がどのような影響を与えるかを調べてください。最初にで除外することができますwhere num is not null

ここから、次の方法で目的の結果を得ることができます。

select * from t where (num, text) in ( *insert query above* )

または結合を使用:

select t1.* from t t1,
    (select text, min(num) as n from t group by text) t2
where t1.num = t2.n and t1.text = t2.text.

また、テーブルのパフォーマンスが十分でない場合は、より複雑なステートメントの調査を開始します。


-2

このクエリは、正確に必要なものではありませんか?

select min(num), text, num2 group by text, num2

num2値は一意であるため、4つのレコードすべてが返されます。
CL。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.