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

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

新規登録して質問してみよう
ただいま回答率
85.35%
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回答

2923閲覧

MySQLでROW_NUMBERの機能がほしい

ikatako

総合スコア270

MySQL

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

SQL

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

0グッド

0クリップ

投稿2020/11/13 10:06

編集2020/11/13 19:48

###実現したいこと
スレッドのコメントランキングをUPDATEしたいです。

コメントへの評価を上げる|下げるというアクションがありまして、スレッドのグループごとに、この合計点でランキングをつけて、rankingカラムをUPDATEする処理になります。

ただ合計点が同値の場合、ランキングは同位にはせず連番にしたいです。

###問題点
ランキングのUPDATEはできたのですが、合計点が同値の場合、ランキングも同位になってしまいます。

たとえば次のp_commentsというテーブルにrankingを入れたいわけですが、
super_ID=3(39行目)にコメントがあるように
# 合計点は 3-4=-1 であり、ranking は 2 にしたいが 1 となる
というのが問題です。

このsuper_ID=3super_ID=8と同じ-1という合計点なので確かに同位ではあるのですが、今回はsuper_IDが大きいものを上位とし、
super_ID=8(42行目)のrankingを1位にして
super_ID=3(39行目)のrankingを2位にしたいのです。

###前提のテーブル構成

テーブルは次の5つで構成されます。
-- 投稿 (スーパータイプ)
-- 投稿 (サブタイプ/スレッド)
-- 投稿 (サブタイプ/コメント)
-- 評価を上げる
-- 評価を下げる

sql

1-- 投稿 (スーパータイプ) 2CREATE TABLE p_supers 3 (`ID` int, `kind_id` int, `sentence` varchar(1000), primary key(`ID`)) 4; 5INSERT INTO p_supers 6 (`ID`, `kind_id`, `sentence`) 7VALUES 8 (1, 1, '猫について語りましょう') 9 ,(2, 1, '犬について語りましょう') 10 ,(3, 2, '猫はいいです') 11 ,(4, 2, 'たしかに猫は最高です') 12 ,(5, 1, '鰐について語りましょう') 13 ,(6, 2, '鰐は怖いです') 14 ,(7, 2, '鰐はやわらかいです') 15 ,(8, 2, '猫は液体です') 16 ,(9, 2, '猫は液体ではないです') 17 ,(10, 2, '鰐は怖くないです') 18; 19 20-- 投稿 (サブタイプ/スレッド) 21CREATE TABLE p_threads 22 (`super_ID` int, `title` varchar(100), primary key(`super_ID`)) 23; 24INSERT INTO p_threads 25 (`super_ID`, `title`) 26VALUES 27 (1, '猫スレ') 28 ,(2, '犬スレ') 29 ,(5, '鰐スレ') 30; 31 32-- 投稿 (サブタイプ/コメント) 33CREATE TABLE p_comments 34 (`super_ID` int, `thread_ID` int, `up_count` int, `down_count` int, `ranking` int, primary key(`super_ID`)) 35; 36INSERT INTO p_comments 37 (`super_ID`, `thread_ID`, `up_count`, `down_count`, `ranking`) 38VALUES 39 # ranking カラムは該当のソースコードを実行すると、次のコメントのようになる 40 (3, 1, 3, 4, 0) # 合計点は 3-4=-1 であり、ranking は 2 にしたいが 1 となる 41 ,(6, 5, 1, 1, 0) # 合計点は 1-1=0 であり、ranking は 2 となる 42 ,(7, 5, 2, 0, 0) # 合計点は 2-0=2 であり、ranking は 1 となる 43 ,(8, 1, 1, 2, 0) # 合計点は 1-2=-1 であり、ranking は 1 となる 44; 45 46-- 評価を上げる 47CREATE TABLE a_up_comments 48 (`users_ID` int, `comment_ID` int, `created_at` datetime 49 , foreign key (`comment_ID`) references p_comments(`super_ID`)) 50; 51INSERT INTO a_up_comments 52 (`users_ID`, `comment_ID`, `created_at`) 53VALUES 54 (3, 3, '2020-12-01 12:00:00.000001') 55 ,(4, 3, '2020-12-01 12:00:00.000002') 56 ,(1, 7, '2020-12-01 12:00:00.000003') 57 ,(1, 3, '2020-12-01 12:00:00.000004') 58 ,(2, 6, '2020-12-01 12:00:00.000005') 59 ,(1, 7, '2020-12-01 12:00:00.000006') 60 ,(2, 8, '2020-12-01 12:00:00.000007') 61; 62 63-- 評価を下げる 64CREATE TABLE a_down_comments 65 (`users_ID` int, `comment_ID` int, `created_at` datetime 66 , foreign key (`comment_ID`) references p_comments(`super_ID`)) 67; 68INSERT INTO a_down_comments 69 (`users_ID`, `comment_ID`, `created_at`) 70VALUES 71 (1, 3, '2020-12-02 12:00:00.000001') 72 ,(4, 3, '2020-12-02 12:00:00.000002') 73 ,(5, 8, '2020-12-02 12:00:00.000003') 74 ,(1, 3, '2020-12-02 12:00:00.000004') 75 ,(3, 3, '2020-12-02 12:00:00.000005') 76 ,(1, 8, '2020-12-02 12:00:00.000006') 77 ,(2, 6, '2020-12-02 12:00:00.000007') 78; 79 80# ranking を更新 81update p_comments as t0 82inner join ( 83 # thread_ID のグループで ranking の順位を取得 84 select super_ID, up_count, down_count, ( 85 select count(*) +1 86 from p_comments as t2 87 where 1 88 and ( t2.up_count - t2.down_count ) > ( t1.up_count - t1.down_count ) 89 and t2.thread_ID = t1.thread_ID 90 ) as ranking 91 from p_comments AS t1 92) as t3 on t0.super_ID = t3.super_ID 93set t0.ranking = t3.ranking;

###該当のソースコード
こちらが連番でなく同位になるという問題のUPDATEになります。
実行する → http://sqlfiddle.com/#!9/b0b213/1

SQL

1# ranking を更新 2update p_comments as t0 3inner join ( 4 # thread_ID のグループで ranking の順位を取得 5 select super_ID, up_count, down_count, ( 6 select count(*) +1 7 from p_comments as t2 8 where 1 9 and ( t2.up_count - t2.down_count ) > ( t1.up_count - t1.down_count ) 10 and t2.thread_ID = t1.thread_ID 11 ) as ranking 12 from p_comments AS t1 13) as t3 on t0.super_ID = t3.super_ID 14set t0.ranking = t3.ranking;

###試したこと
該当のソースコードを使い同位のrankingを入れるのはひとまずよしとして、それが終わった後で改めて別の処理で連番にする。という風に下記の流れでならできますが、

SQL

1select 2 (select count(*)+1 3 from p_comments 4 where thread_ID = x.thread_ID and super_ID > x.super_ID 5 ) as 'No.' 6 , super_ID, thread_ID 7from p_comments as x 8order by x.thread_ID, x.ranking desc

こうして別の処理にせず、該当のソースコードのUPDATEのクエリ1回で済ませたく思って質問させて頂きました。

もしそれができましたらご教示いただけますと幸いです。
宜しくお願いいたします。

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

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

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

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

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

yambejp

2020/11/13 10:29

IDはprimaryにしていないのですか?(uniqueなnot nullなintというだけでもいいですが) あとはMySQLのバージョンを明記ください
ikatako

2020/11/13 10:50

すみません、仰る通りIDはprimaryでした。(該当のソースコードを編集いたしました。) MySQLは現状では5.5なので、5.5でできるような方法ですとありがたいです。 しかし頑張れば5.7にできますので、5.7でしか難しければ頑張ります。
yambejp

2020/11/13 10:53

5.5だと環境的にちょっと厳しいですね、せめて5.7.6以降なら生成列という仕組みが使えるんですが・・・ わりきってビューでやるという考え方もありますね
guest

回答1

0

ベストアンサー

※ランクカラムを設定する

SQL

1CREATE TABLE p_comments 2(super_ID int unique, 3thread_ID int, 4up_count int, 5down_count int, 6rank int null); 7 8INSERT INTO p_comments 9(super_ID, thread_ID, up_count, down_count) 10VALUES 11(3, 1, 3, 4), 12(6, 5, 1, 1), 13(7, 5, 2, 0), 14(8, 1, 1, 2); 15 16 17insert into p_comments(super_ID,rank) select super_ID,( 18select count(*)+1 from p_comments 19where up_count-down_count-t1.up_count+t1.down_count<0 or 20(up_count-down_count-t1.up_count+t1.down_count=0 and super_ID<t1.super_ID) ) as rank 21from p_comments as t1 22on duplicate key update rank=values(rank)

投稿2020/11/13 10:55

編集2020/11/13 16:23
yambejp

総合スコア116724

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

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

yambejp

2020/11/13 10:57

select *,( select count(*)+1 from p_comments where up_count-down_count-t1.up_count+t1.down_count<0 or (up_count-down_count-t1.up_count+t1.down_count=0 and super_ID<t1.super_ID) ) as rank from p_comments as t1
ikatako

2020/11/13 11:38

UPDATEするならこうするという意味ですよね? update p_comments as t0 inner join ( # ここにご回答を書く ) as t3 on t0.super_ID = t3.super_ID set t0.ranking = t3.rank; 実行しますとrankingカラムに値は入ったものの、up_countとdown_countの計算結果に応じてのランキングにならず、super_IDと同じ並びの数字が入りました。 そして入った数字も連番でなくとびとびで、例えば supers_IDの値に 1, 7, 12 と入っていたら、 rankingの値は 11, 17, 22 ととびとびに入るという不思議な結果でした。
yambejp

2020/11/13 16:24

回答を修正版に書き換えました
ikatako

2020/11/13 20:47 編集

ご修正どうもありがとうございます。あと「>スレッドのグループごとに」という条件の方だけいかがでしょうか。 ご回答の結果↓はすべてでランク付けされますが、 super_ID, thread_ID, rank 3, 1, 1 6, 5, 3 7, 5, 4 8, 1, 2 目的↓はthread_IDが同じグループでランクの付けしたかったという点です。 super_ID, thread_ID, rank 3, 1, 2 6, 5, 2 7, 5, 1 8, 1, 1
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問