質問するログイン新規登録
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQL

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

Q&A

解決済

1回答

1723閲覧

MySQLで重複をはじいて当選者を抽出

suzushin0619

総合スコア10

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQL

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

0グッド

1クリップ

投稿2023/04/13 11:01

編集2023/04/14 02:15

0

1

実現したいこと

何かの懸賞のようなイメージで以下の様な応募履歴テーブル(drawings)があったとします。
この中からランダムで2名を当選者として抽出したいです。

※1レコードが応募1口

iduser_idcreated
1232023-02-16
2452023-02-19
3452023-02-22
4992023-02-24
5622023-02-26
6232023-03-01
7992023-03-04
8452023-03-09
9232023-03-11
10232023-03-14

前提

応募してきた数だけ当選確率が上がるようなSQLを作りたいです。
例えば、user_id:23は4回応募してきているので、1回応募の人より4倍の確率で抽出されるようにしたいです。

ただし、重複をはじいて当選者を抽出したいです。
何回応募しても確率は上がりますが同じuser_idが2件抽出されることが無いようにしたいです。

発生している問題・エラーメッセージ

当初以下の様なSQLを思いついたのですが、 ORDER BY RAND()GROUP BY の後に実行されるため、応募口数が無視されることに気づきました。
また DISTINCT を利用しても同様だと思います。

重み付き抽選のようなことがSQLで再現できればと思っています。

sql

1SELECT 2 * 3FROM 4 drawings 5GROUP BY user_id 6ORDER BY RAND() 7LIMIT 2

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

MySQL 8.0 を利用しています

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

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

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

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

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

tmp

2023/04/14 09:03

確率の問題ではないですよね? 抽選の1回あたり当選率が応募数nに応じて確率がn倍ですよね?(2名なので2回抽選) ガチャとか確率で問題になるのでちょっと気になりました。
suzushin0619

2023/04/14 09:19

> 抽選の1回あたり当選率が応募数nに応じて確率がn倍ですよね? はい、応募数nに応じて確率がn倍としたいです。 > (2名なので2回抽選) 今回は簡略化するために2名としましたが、仮に重複のない100名を応募者からピックアップする場合に100回抽選するのが手間だと思い、1度のSQLで取得する方法がないかなと模索しています。
tmp

2023/04/14 10:13

単に抽選2回(2名)当選率だと、 この例の10応募データ場合、応募数1だと20%で応募数2だと37.7%になり、2倍にはならない、 そこで応募数2で2倍になりますとか、単純に宣伝してしまうと詐欺だという人がでてくるかもしれないのでコメントしました。
suzushin0619

2023/04/14 14:41

実際はB2Cなサービスで利用するわけではなく、社内ツールで今回のようなSQLが必要となり、わかりやすくするために懸賞のような表現を用いました。 ただ、ロジックや仕様を説明するときに「〇倍の確率で」と謳うと仰る通り語弊が生まれそうですね..汗 補足をして頂きありがとうございました!
guest

回答1

0

ベストアンサー

普通にorder by rand()して上位2名(LIMIT 2)をとればいいだけですね
複数いればそれだけ確率はあがります。
ただし、同じ人間が2度あたる可能性もあるので、結果に対してダブりが
あった場合再抽選するのがわかりやすい気がします

追記

SQL

1create table tbl(id int primary key auto_increment,user varchar(10),rank double); 2 3insert into tbl(user,rank) values 4('a',rand()), 5('a',rand()), 6('b',rand()), 7('b',rand()), 8('a',rand()), 9('a',rand()), 10('c',rand()), 11('d',rand()); 12 13select user,min(rank) as min_rank from tbl group by user order by min_rank;

上記当選者分でLimitを指定すればよいでしょう

投稿2023/04/13 11:19

編集2023/04/14 02:14
yambejp

総合スコア118073

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

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

suzushin0619

2023/04/14 02:06 編集

ご回答ありがとうございます! ちなみに同じ人間が2度当たる事を防ぐSQLは可能でしょうか? 今は当選者を2人としていますが、仮に1000人の当選者を選ぶ場合は再抽選を繰り返し行う必要が出てしまいそうで、重複の当選者を防ぐ様なSQL1発で取得できたらと思っています。
yambejp

2023/04/14 03:12 編集

テーブルの構成を調整すればいけそうですね。追記しておきます 追記:randは都度発生するみたいなのでテーブルの構造変えなくても大丈夫かも select user_id,min(rand()) as min_rand from tbl group by user_id order by min_rand asc limit 2
suzushin0619

2023/04/14 09:27

追記ありがとうございます! 頂いたSQLをテストしたところうまく動いているように思えます。 ただ、なんとなくロジックを理解しているような状態です(脳みそが足らずスミマセン...笑) 頭の中で整理完了したらベストアンサーをお渡しして質問をクローズさせて頂きたく思います。
suzushin0619

2023/04/14 09:37

理解できました こちらの要望通りのご回答かつSQLのテクニックを学べました ありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.30%

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

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

質問する

関連した質問