-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsql_answer.sql
More file actions
407 lines (373 loc) · 8.36 KB
/
sql_answer.sql
File metadata and controls
407 lines (373 loc) · 8.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
サブクエリ & EXISTS
1-1 1回の注文が3000円以上の購入者のリスト(customer_id)を出力
SELECT
ors.customer_id
FROM
orders ors
WHERE
(
SELECT
SUM(oi.total)
FROM
order_item oi
WHERE
oi.order_id = ors.order_id
) >= 3000;
1-2 ヘッドと明細とで検索句を取りたい場合
SELECT
ors.*
FROM
orders ors
WHERE
EXISTS
(
SELECT
order_item_id
FROM
order_item oi
WHERE
oi.order_id = ors.order_id
AND
oi.item_id = 13
)
1-3 未納データ
SELECT
DISTINCT t1.customer_id
FROM
tainousha t1
WHERE
NOT EXISTS
(
SELECT
*
FROM
tainousha t2
WHERE
t2.customer_id = t1.customer_id
AND
t2.invoice_month BETWEEN '2017-06-01' AND '2017-08-01'
AND
t2.payment_status = 10
);
1-4 ランク重複を含んだ処理
SELECT
p1.name,
p1.price,
(
SELECT
COUNT(p2.name)
FROM
products p2
WHERE
p2.price > p1.price
)+1 AS order_rank
FROM products p1
ORDER BY order_rank
*Postgres window関数使用
SELECT
name,
price,
RANK() OVER ( ORDER BY price DESC ) AS rank1,
DENSE_RANK() OVER ( ORDER BY price DESC ) AS rank2
FROM
products;
2-1 総当たりを求めよ
自分を含んだ総当たり
SELECT
b1.team as myself,
b2.team as opponet
FROM
baseball b1, baseball b2
自分を除いてorderbyをかける forのなかのifのような感じ
SELECT
b1.team as myself,
b2.team as opponet
FROM
baseball b1, baseball b2
WHERE
b1.team <> b2.team
ORDER BY
b1.team
(下記と同じ)
SELECT
b1.team as myself,
b2.team as opponent
FROM
baseball b1
CROSS JOIN
baseball b2
ON
b1.team <> b2.team
ORDER BY
b1.team
* onに下記のようにかくと重複を防げる
b1.team <> b2.team and b1.team > b2.team
2-2 前年売り上げとの比較をせよ
//総当たり
SELECT
sa.year as this_year,
sa.sale as this_sale,
sb.year as comp_year,
sb.sale as comp_sale
FROM
sales sa,sales sb
ORDER BY
this_year
//この中で自分の年-1を取得
SELECT
sa.year as this_year,
sa.sale as this_sale,
sb.year as comp_year,
sb.sale as comp_sale
FROM
sales sa,sales sb
WHERE
sa.year- 1 = sb.year
ORDER BY
this_year
(1900年もでる)
SELECT
sa.year as this_year,
sa.sale as this_sale,
sb.year as comp_year,
sb.sale as comp_sale
FROM
sales sa
LEFT JOIN
sales sb
ON
sa.year- 1 = sb.year
ORDER BY
this_year
2-3 集計表
SELECT
age.age_range,
sex.sex
FROM
tblAge age ,tblSex sex
ORDER BY
age.age_range
SELECT
age.age_range,
sex.sex
FROM
tblAge age
CROSS JOIN
tblSex sex
ORDER BY
age.age_range
結合
https://qiita.com/Yinaura/items/3ab6fc49ae55f52e2d55
http://nullnote.com/programs/mysql/join/
3-1
都市問題
SELECT
pref,
population,
CASE
WHEN population < 100 THEN '小都市'
WHEN population >= 100 and population < 500 THEN '中都市'
WHEN population >= 500 THEN '大都市'
ELSE NULL END AS city_rank
FROM population;
SELECT
CASE
WHEN population < 100 THEN '小都市'
WHEN population >= 100 and population < 500 THEN '中都市'
WHEN population >= 500 THEN '大都市'
ELSE NULL END AS city_rank,
count(*) as cnt
FROM population
GROUP BY city_rank;
3-2
講座開設
SELECT
course_name ,
(SELECT COUNT(oc.course_id) FROM openCourses oc WHERE oc.month='200706' AND oc.course_id =cm.course_id) AS "200706",
(SELECT COUNT(oc.course_id) FROM openCourses oc WHERE oc.month='200707' AND oc.course_id =cm.course_id) AS "200707",
(SELECT COUNT(oc.course_id) FROM openCourses oc WHERE oc.month='200708' AND oc.course_id =cm.course_id) AS "200708"
FROM
courseMaster cm
CASE式で○×
SELECT
course_name ,
(CASE WHEN (SELECT COUNT(oc.course_id) FROM openCourses oc WHERE oc.month='200706' AND oc.course_id =cm.course_id) = 1 THEN '○' ELSE '-' END )AS "200706",
(CASE WHEN (SELECT COUNT(oc.course_id) FROM openCourses oc WHERE oc.month='200707' AND oc.course_id =cm.course_id) = 1 THEN '○' ELSE '-' END )AS "200707",
(CASE WHEN (SELECT COUNT(oc.course_id) FROM openCourses oc WHERE oc.month='200708' AND oc.course_id =cm.course_id) = 1 THEN '○' ELSE '-' END )AS "200708"
FROM
courseMaster cm
3-3
SELECT
sa.year as this_year,
CASE
WHEN sa.sale - sb.sale > 0 THEN '↑'
WHEN sa.sale - sb.sale = 0 THEN '='
WHEN sa.sale - sb.sale < 0 THEN '↓'
ELSE '-' END as diff
FROM
sales sa
LEFT JOIN
sales sb
ON
sa.year- 1 = sb.year
ORDER BY
this_year
4 having基礎 三人以上のクラスは
whereとの違い
GROUP BYで絞った後の抽出
https://dev.classmethod.jp/server-side/db/difference-where-and-having/
4-1
SELECT
class,
COUNT(*)
FROM
students
GROUP BY
class
HAVING COUNT(*) >= 3
4-2 商品を全て含む
SELECT
si.shop,
si.item as shop_item,
i.item as item
FROM
shopItems si
LEFT JOIN
items i
ON
si.item = i.item
SELECT
si.shop
FROM
shopItems si
LEFT JOIN
items i
ON
si.item = i.item
GROUP BY
si.shop
HAVING COUNT(i.item) >= (SELECT COUNT(i2.item) FROM items i2)
4-3 点数問題
EXISTSのみ
SELECT
DISTINCT(ts1.student_id)
FROM
testScores ts1
WHERE
EXISTS ( SELECT * FROM testScores ts2 WHERE ts2.student_id = ts1.student_id AND ts2.subject="国語" and ts2.score >= 80)
AND EXISTS ( SELECT * FROM testScores ts3 WHERE ts3.student_id = ts1.student_id AND ts3.subject="算数" and ts3.score >= 50)
havingのみ(わかりやすくSUMをSELECT句に出す)
SELECT
ts1.student_id,
SUM( ( CASE WHEN ts1.subject = '国語' and ts1.score >= 80 THEN 1 ELSE 0 END )) AS pass_1 ,
SUM( ( CASE WHEN ts1.subject = '算数' and ts1.score >= 50 THEN 1 ELSE 0 END )) AS pass_2
FROM
testScores ts1
GROUP BY
ts1.student_id
HAVING pass_1 = 1 AND pass_2 = 1
まずは性別、年齢テーブル
SELECT
age.age_class,
age.age_range,
sex.sex_cd,
sex.sex
FROM
tblAge age ,tblSex sex
( tblAge age CROSS JOIN tblSex sex )
ORDER BY
age.age_range
人口テーブルと結合
SELECT
pop.pref_name,
T1.*,
pop.population
FROM (
SELECT
age.age_class,
age.age_range,
sex.sex_cd,
sex.sex
FROM
tblAge age ,tblSex sex
ORDER BY
age.age_range ) T1
LEFT JOIN
tblPop pop
ON
T1.age_class = pop.age_class AND
T1.sex_cd = pop.sex_cd
地区別人口分類
SELECT
pop.pref_name,
T1.*,
pop.population,
CASE WHEN pref_name IN ('千葉','東京') THEN pop.population ELSE 0 END AS '関東',
CASE WHEN pref_name IN ('秋田','青森') THEN pop.population ELSE 0 END AS '東北'
FROM (
SELECT
age.age_class,
age.age_range,
sex.sex_cd,
sex.sex
FROM
tblAge age ,tblSex sex
ORDER BY
age.age_range ) T1
LEFT JOIN
tblPop pop
ON
T1.age_class = pop.age_class AND
T1.sex_cd = pop.sex_cd
最終形
SELECT
T1.age_range,
T1.sex,
SUM( CASE WHEN pref_name IN ('秋田','青森') THEN pop.population ELSE 0 END ) AS '東北',
SUM( CASE WHEN pref_name IN ('千葉','東京') THEN pop.population ELSE 0 END ) AS '関東'
FROM (
SELECT
age.age_class,
age.age_range,
sex.sex_cd,
sex.sex
FROM
tblAge age ,tblSex sex
ORDER BY
age.age_range ) T1
LEFT JOIN
tblPop pop
ON
T1.age_class = pop.age_class AND
T1.sex_cd = pop.sex_cd
GROUP BY T1.age_class, T1.sex_cd DESC
高速化のコツ
1.問題点の発見(slow_query_logや直書きでの測定、フレームワークのデバッガなど)
2.主な対策
2-1 SQL自体を減らす、改善する
キャッシュの活用する
ぐるぐる系→ガツン系へ
SELECT句で*を使わない→カラム数が特に多いものに注意。メモリへの負担を考える
2-2 インデックスを貼る
EXPLAINによる解析→ボトルネックの発見
・rowsの数を少なくする
・select_typeがALLかindexになっているものがボトルネック→indexを貼る
indexが効かないポイント
データが少ないケース(数千程度)
like検索の中間一致、後方一致、否定形、is null、OR、暗黙の型変換(数値を文字列のように扱う)
Nested Loopに関して
https://qiita.com/yuku_t/items/208be188eef17699c7a5
//ボトルネックの検索EXPLAIN
alter table customers add index zip(zip);
alter table postcode add index zip(zip);
alter table customers drop index zip;
alter table postcode drop index zip;
130~150ms → 1~0.5ms
SELECT
*
FROM
customers c
LEFT JOIN
postcode p
ON
c.zip = p.zip;