回答編集履歴

2

MySQL<8.0 での手法を追記。

2018/08/24 12:50

投稿

hope_mucci
hope_mucci

スコア4447

test CHANGED
@@ -1,3 +1,7 @@
1
+ ※追記あり。
2
+
3
+ ---
4
+
1
5
  `limit`ついてるし、PostgreSQLですよね?
2
6
 
3
7
 
@@ -41,3 +45,181 @@
41
45
  ```
42
46
 
43
47
  環境が用意できなかったので実際には動かしていません。質問者で文法チェック等して動かしてみてください。
48
+
49
+
50
+
51
+ ---
52
+
53
+ ここから追記。
54
+
55
+ ほう、MySQL5.7とな。
56
+
57
+ 他の方が大勢指摘している通り、SQLはRDBSにより使える構文や関数がかなり異なりますので製品名を明記しないとこのように頓珍漢な回答が返ってくることになります。以後気を付けるようにね。
58
+
59
+
60
+
61
+ で、ウィンドウ関数が使えないMySQL8.0未満は、質問のようなグループごとに集計をかける処理がとっても苦手です。
62
+
63
+ それでも無理やり書いてみたらこんな感じになるでしょう。
64
+
65
+ (account_idごと10件まで取得できることは検証しました。
66
+
67
+  また問題の本質とは関係ないのでaccoutsとclientsのjoinは省略しました)
68
+
69
+ ```SQL
70
+
71
+ select
72
+
73
+ query.account_id
74
+
75
+ ,query.client_id
76
+
77
+ ,query.recommend_date
78
+
79
+ ,query.row_number
80
+
81
+ from(
82
+
83
+ select
84
+
85
+ main_r.account_id
86
+
87
+ ,main_r.client_id
88
+
89
+ ,main_r.recommend_date
90
+
91
+ ,(select
92
+
93
+ count(*)
94
+
95
+ from
96
+
97
+ recommend sub_r1
98
+
99
+ where sub_r1.account_id = main_r.account_id and (
100
+
101
+ (sub_r1.recommend_date < main_r.recommend_date)
102
+
103
+ or (sub_r1.recommend_date = main_r.recommend_date and sub_r1.client_id > main_r.client_id))
104
+
105
+ ) +1 row_number
106
+
107
+ from
108
+
109
+ recommend main_r
110
+
111
+ order by row_number
112
+
113
+ ) query
114
+
115
+ where query.row_number <= 10
116
+
117
+ order by account_id,row_number
118
+
119
+ ;
120
+
121
+ ```
122
+
123
+ count(*)があるサブクエリでrow_number相当の処理をやっています。比較条件を1つずつバラして書くのが大変です。
124
+
125
+ 今回の件ではまだ条件が単純なのでcountとwhere句でやっつけられていますが、もっと複雑な集計条件になると黒魔術なSQLが爆誕することでしょう。
126
+
127
+
128
+
129
+ グループから上位N件を取得するクエリの作成は、皆さん本当に苦労されていて、
130
+
131
+ teratailの過去質問でも例えば[これとか、](https://teratail.com/questions/23111)はたまた[こんなのとか](https://teratail.com/questions/121746)いろいろあるのですが、どの質問も「クエリがエレガントじゃねぇなあ」とぼやきながら回答されてます。
132
+
133
+ 本件も私の正直なところ、クエリをフェッチした先で1行ずつ番号付けながら読み込み、同じaccount_id の 11件目以降は読み飛ばすみたいな処理をしたほうが精神衛生上遥かにマシだと考えています。(多分PHPとかrailsとか使っていますよね)
134
+
135
+ 今回の問題は上にかいたもので解決できますが、実際に作るクエリはこれ1つではないと思いますし、取得先で集計作業したほうがきっと楽ですよ、とお伝えしておきます。
136
+
137
+
138
+
139
+ 以下検証用。
140
+
141
+ ```
142
+
143
+ CREATE TABLE `recommend` (
144
+
145
+ `account_id` int(11) DEFAULT NULL,
146
+
147
+ `client_id` int(11) DEFAULT NULL,
148
+
149
+ `recommend_date` varchar(8) DEFAULT NULL
150
+
151
+ ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
152
+
153
+ insert into db.recommend values (1,1,'20180101');
154
+
155
+ insert into db.recommend values (1,1,'20180201');
156
+
157
+ insert into db.recommend values (1,1,'20180301');
158
+
159
+ insert into db.recommend values (1,2,'20180101');
160
+
161
+ insert into db.recommend values (1,2,'20180201');
162
+
163
+ insert into db.recommend values (1,2,'20180301');
164
+
165
+ insert into db.recommend values (1,3,'20180101');
166
+
167
+ insert into db.recommend values (1,3,'20180201');
168
+
169
+ insert into db.recommend values (1,3,'20180301');
170
+
171
+ insert into db.recommend values (2,1,'20180102');
172
+
173
+ insert into db.recommend values (2,1,'20180202');
174
+
175
+ insert into db.recommend values (2,1,'20180302');
176
+
177
+ insert into db.recommend values (2,2,'20180102');
178
+
179
+ insert into db.recommend values (2,2,'20180202');
180
+
181
+ insert into db.recommend values (2,2,'20180302');
182
+
183
+ insert into db.recommend values (2,3,'20180102');
184
+
185
+ insert into db.recommend values (2,3,'20180202');
186
+
187
+ insert into db.recommend values (2,3,'20180302');
188
+
189
+ insert into db.recommend values (1,11,'20180101');
190
+
191
+ insert into db.recommend values (1,11,'20180201');
192
+
193
+ insert into db.recommend values (1,11,'20180301');
194
+
195
+ insert into db.recommend values (1,12,'20180101');
196
+
197
+ insert into db.recommend values (1,12,'20180201');
198
+
199
+ insert into db.recommend values (1,12,'20180301');
200
+
201
+ insert into db.recommend values (1,13,'20180101');
202
+
203
+ insert into db.recommend values (1,13,'20180201');
204
+
205
+ insert into db.recommend values (1,13,'20180301');
206
+
207
+ insert into db.recommend values (2,11,'20180102');
208
+
209
+ insert into db.recommend values (2,11,'20180202');
210
+
211
+ insert into db.recommend values (2,11,'20180302');
212
+
213
+ insert into db.recommend values (2,12,'20180102');
214
+
215
+ insert into db.recommend values (2,12,'20180202');
216
+
217
+ insert into db.recommend values (2,12,'20180302');
218
+
219
+ insert into db.recommend values (2,13,'20180102');
220
+
221
+ insert into db.recommend values (2,13,'20180202');
222
+
223
+ insert into db.recommend values (2,13,'20180302');
224
+
225
+ ```

1

ソースに誤字があったので修正

2018/08/24 12:50

投稿

hope_mucci
hope_mucci

スコア4447

test CHANGED
@@ -16,13 +16,13 @@
16
16
 
17
17
  select * -- ← *は止めて必要な列を列挙すること
18
18
 
19
- , row_number() over (pertition by recccomend.account_id order by recommend_date, recommend.client_id desc) recommend_order
19
+ , row_number() over (pertition by recommend.account_id order by recommend_date, recommend.client_id desc) recommend_order
20
20
 
21
- from recommend
21
+ from recommend
22
22
 
23
- left join accounts on accounts.id = recommend.account_id
23
+ left join accounts on accounts.id = recommend.account_id
24
24
 
25
- left join clients on clients.id = recommend.client_id
25
+ left join clients on clients.id = recommend.client_id
26
26
 
27
27
  order by recommend_date, recommend.client_id desc
28
28