質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
SQLite

SQLiteはリレーショナルデータベース管理システムの1つで、サーバーではなくライブラリとして使用されている。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

3回答

2281閲覧

SQLで重複した要素を無視してselectを行いたい。この時、得点が最も高い行のみを抽出したい。

nemumi-nomaki

総合スコア20

SQLite

SQLiteはリレーショナルデータベース管理システムの1つで、サーバーではなくライブラリとして使用されている。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

0クリップ

投稿2020/06/17 15:51

編集2020/06/17 16:34

前提・実現したいこと

下図右側のようなtableがあるとき、ここからユーザ名の重複を除外してselectを行いたいです。ただしこの時、得点が最も高い行のみを残し、他を除外するようにしたいです。
同じ得点・同じユーザ名の列が複数ある場合は、そのうち一つだけを残したいです。
どのようなSQL文を書けばよいですか?ご教授ください。
イメージ説明

補足情報(FW/ツールのバージョンなど)

SQLite3を利用しています。

サンプル作成に使ったSQL文は以下の通りです。

SQL

1create table Test (id INTEGER PRIMARY KEY AUTOINCREMENT,user_name TEXT NOT NULL, score INTEGER NOT NULL ); 2insert into Test(user_name, score) values ("A",10); 3insert into Test(user_name, score) values ("B",5); 4insert into Test(user_name, score) values ("C",20); 5insert into Test(user_name, score) values ("A",15); 6insert into Test(user_name, score) values ("A",5);

ユーザ名のTableはありません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sousuke

2020/06/17 16:07

tableのcreate文やサンプルデータのinsert文などあると回答しやすいです。 ユーザーのテーブルはないんですか?
nemumi-nomaki

2020/06/17 16:19

ご指摘ありがとうございます。SQL文を追加いたしました。ユーザーのテーブルはありません。
guest

回答3

0

ベストアンサー

分析関数のRANK()が使えますね。

SQL

1select * 2from ( 3 select * 4 , rank() over(partition by user_name order by score desc, id) as rnk 5 from test 6) tmp 7where rnk=1

投稿2020/06/17 17:16

sazi

総合スコア25174

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nemumi-nomaki

2020/06/19 13:00

互換性とパフォーマンスを考慮して、ベストアンサーとさせていただきました。ご回答ありがとうございました。
guest

0

これで取れると思います。

sql

1select * 2from Test 3group by user_name 4having max(score)

投稿2020/06/17 16:20

編集2020/06/17 16:39
htsign

総合スコア870

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sazi

2020/06/17 17:20

havingが条件になっていないし、そもそもgroup by でselect * はエラーです。
htsign

2020/06/17 17:29

おかしいですね。 $ sqlite3 -version 3.22.0 2018-01-22 18:45:57 0c55d179733b46d8d0ba4d88e01a25e10677046ee3da1d5b1581e86726f2alt1 この環境でローカルにデータ作って試した結果を確認しております。何か間違っているんでしょうか?
sazi

2020/06/17 17:36

それは失礼しました。逆に私の手元には無いのでpostgresで確認しています。 having max(socore) とするとmaxの行のみになるんですか? その場合同点ではどうなりますか?
sazi

2020/06/17 17:41

group by 指定していない項目は適当(先頭とか最後とか)に表示されるんじゃないでしょうか?
htsign

2020/06/17 18:08

試してみました。 > その場合同点ではどうなりますか? 最大の score を持つ行のうち(SQLite3の仕様を把握していないのでおそらくとしか言えませんが)insert順で最初のものが取れてきます。 これはダメですね。ご指摘いただいてありがとうございました。 > group by 指定していない項目は適当(先頭とか最後とか)に表示されるんじゃないでしょうか? これは仰る意味がよく分かりませんでした。 「カラム順が user_name, id, score になるんじゃないか?」ということでしょうか? そういう意味であれば、いいえ、テーブルに定義された順で取れます。 それとも「 group by 指定のないカラムの値はそれに適合した行のうち取れるものが分からないのではないか?(例えば最大の score が 80 だとして、score が 80 の行にそれぞれ id が 5 と 6 のものがあるとすれば、5 が取れるか 6 が取れるか分からないのではないか)」ということでしょうか? それであれば上でお応えした通りです。
sazi

2020/06/18 00:22 編集

havingについては、「having 式」なので、max()のみだと、真偽判定では必ず値があるから全て真になっているのではないでしょうか。 つまり、having max()があっても無くても結果は変わらないのではないかと思われます。
htsign

2020/06/18 00:34

変わりました。 sqlite> select * from Test; 1|A|10 2|B|5 3|C|20 4|A|15 5|A|5 6|A|20 7|A|20 8|C|10 このデータを持つテーブルがある中で sqlite> select * from Test group by user_name; 7|A|20 2|B|5 8|C|10 sqlite> select * from Test group by user_name having max(score); 6|A|20 2|B|5 3|C|20 となります。 申し訳ないのですが、一度手元で確認していただけないでしょうか。 ほとんどのパッケージマネージャリポジトリには含まれているはずですから簡単にインストールできますし(バージョンが多少古いとかはあるかもしれませんが)それが面倒でもオンラインで簡易実行する環境もある昨今です。 https://sqliteonline.com/ https://extendsclass.com/sqlite-browser.html など。
sazi

2020/06/18 00:52 編集

何となく動作が見えました。 having max(score) だけでは意図通りでは無いという事も。 お節介は終わりにします。
nemumi-nomaki

2020/06/18 11:07

すいません、私は全然動作が見えていないのですが、宜しければ教えていただけませんか。 なぜ条件式ではないhaving max(score)で最大値が取れるのでしょうか。(確認しましたがちゃんと取れました) SQLite3の規格で動作が定まっていて、必ずそうなる、というものなのでしょうか。 それともたまたま上手くいっているだけで、動作は保証されていないのでしょうか。
htsign

2020/06/18 11:44

ハッキリ言ってしまえば、確かにたまたまです。 書いたときは「あ、なんか動いた」程度の根拠でコメントしました。すみません。 ただ、改めて公式ドキュメントを漁ると、SELECT句の一節に "3. Generation of the set of result rows." という章 ( https://www.sqlite.org/lang_select.html#resultset ) があり、ここにHAVING句が使われた際の説明として "If the HAVING clause is an aggregate expression, it is evaluated across all rows in the group." と書かれています。 まさに今のシチュエーションになっています。一応 documented な動作になっているようです。 しかし @sazi さんがツッコミくださったように、確かに他のRDBではエラーになるクエリです。 個人開発でなく他のメンバーもいる場合などで、無難な実装を目指すのであれば避けたほうがよいかもしれませんね。
nemumi-nomaki

2020/06/19 12:58

なるほど、SQLiteに限ればdocumentedな動作なんですね。ご説明ありがとうございます。
guest

0

みんな大好きnot exists

sql

1CREATE TABLE Score 2 ( 3 id integer primary key, 4 userName varchar(20), 5 userScore int 6 ); 7 8INSERT INTO Score (id, userName, userScore) 9VALUES (1, 'A', 10); 10 11INSERT INTO Score (id, userName, userScore) 12VALUES (2, 'B', 5); 13 14INSERT INTO Score (id, userName, userScore) 15VALUES (3, 'C', 20); 16 17INSERT INTO Score (id, userName, userScore) 18VALUES (4, 'A', 15); 19 20INSERT INTO Score (id, userName, userScore) 21VALUES (5, 'A', 5); 22 23-- ↑これ用意してくれたら回答しやすいのでSQLの質問するなら用意したほうがいいです。 24 25select * 26from Score as A 27where not exists( 28 select 0 29 from Score as B 30 where B.userName=A.userName 31 and B.userScore>A.userScore 32) 33order by A.userName

同名同点が追加されたので

こうかなあ

sql

1select * 2from Score as A 3where A.id = ( 4 select B.id 5 from Score as B 6 where B.userName=A.userName 7 order by B.userScore desc,B.id 8 limit 1 9) 10order by A.userName

投稿2020/06/17 16:16

編集2020/06/17 18:28
sousuke

総合スコア3828

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sazi

2020/06/17 17:19

同じ得点だと駄目ですね。
sousuke

2020/06/17 18:21 編集

まあそうです。最初はしていなかったですから
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問