web-dev-qa-db-ja.com

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

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

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

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

num21, 2、および4である行を取得したい。テキスト列の一意の値ごとに、numの最小値に基づいて選択を行います。

したがって、text = 'a'の場合、numの最小値は0なので、行1と2が必要です。text = 'b'の場合、numの最小値は1なので、行4が必要です。

Group byのさまざまな組み合わせを使用して、行1および2または行1および4を取得できます。自分のやりたいことを実行するSQLコンポーネントがないように感じますが、それが何であるかを理解することができませんでした。

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

可能な解決策

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

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         
8
user35292

ご覧のとおり、単純な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にインデックスを付ける必要があります。 (または、textnumの両方にインデックスを使用して カバーするインデックス を取得します。)

9
CL.

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

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
KISS

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

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

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

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

(これはhavingクエリと同等である必要があります。numがNULLに等しい行を確認するのは興味深いかもしれません。より正確には、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.

また、テーブルのパフォーマンスが十分でない場合は、より複雑なステートメントを調べてください。

1
Grimaldi