Условие
Четыре мини-задачи:
- SQL: из
city_population(city, population)найти город с минимальным населением. - SQL: из таблицы
(ID, Name, Val)сделать пивот →(ID, A, B, C)(значениеVal). - SQL: Retention 1/3/7 дней по пользователям с группировкой по месяцу установки (с января 2022). Таблицы:
user(user_id, installed_at),client_session(user_id, created_at). - Dash (Plotly): дашборд по
games.csvс фильтрами жанров и рейтингов, stacked area по платформам и годам, scatter по оценкам.
Решение
1. Город с минимальным населением
SELECT city, population
FROM city_population
ORDER BY population ASC
LIMIT 1;Альтернатива:
SELECT city, population FROM city_population
WHERE population = (SELECT MIN(population) FROM city_population);2. Pivot
SELECT ID,
MAX(CASE WHEN Name = 'A' THEN Val END) AS A,
MAX(CASE WHEN Name = 'B' THEN Val END) AS B,
MAX(CASE WHEN Name = 'C' THEN Val END) AS C
FROM tbl
GROUP BY ID
ORDER BY ID;В Postgres есть crosstab (extension tablefunc).
3. Retention 1/3/7 по месяцам
WITH base AS (
SELECT u.user_id,
u.installed_at::date AS install_date,
DATE_TRUNC('month', u.installed_at)::date AS install_month
FROM "user" u
WHERE u.installed_at >= DATE '2022-01-01'
),
ret AS (
SELECT b.user_id, b.install_month, b.install_date,
MAX(CASE WHEN s.created_at::date = b.install_date + INTERVAL '1 day' THEN 1 ELSE 0 END) AS r1,
MAX(CASE WHEN s.created_at::date = b.install_date + INTERVAL '3 day' THEN 1 ELSE 0 END) AS r3,
MAX(CASE WHEN s.created_at::date = b.install_date + INTERVAL '7 day' THEN 1 ELSE 0 END) AS r7
FROM base b
LEFT JOIN client_session s ON s.user_id = b.user_id
GROUP BY b.user_id, b.install_month, b.install_date
)
SELECT install_month,
COUNT(*) AS users,
AVG(r1) AS retention_1d,
AVG(r3) AS retention_3d,
AVG(r7) AS retention_7d
FROM ret
GROUP BY install_month
ORDER BY install_month;4. Dash dashboard (Plotly)
import dash
import plotly.express as px
import pandas as pd
from dash import dcc, html, Input, Output
df = pd.read_csv('games.csv')
df = df.dropna()
df = df[df['Year_of_Release'] >= 2000]
app = dash.Dash(__name__)
app.layout = html.Div([
html.H1('Games market dashboard'),
html.P('Описание: дашборд индустрии видеоигр. Фильтры: жанр, рейтинг, годы.'),
dcc.Dropdown(id='genre', options=[{'label': g, 'value': g} for g in sorted(df['Genre'].unique())], multi=True),
dcc.Dropdown(id='rating', options=[{'label': r, 'value': r} for r in sorted(df['Rating'].unique())], multi=True),
dcc.RangeSlider(id='years', min=2000, max=int(df['Year_of_Release'].max()),
step=1, value=[2000, int(df['Year_of_Release'].max())]),
html.Div(id='cnt'),
dcc.Graph(id='area'),
dcc.Graph(id='scatter'),
])
@app.callback(
[Output('cnt', 'children'),
Output('area', 'figure'),
Output('scatter', 'figure')],
[Input('genre','value'), Input('rating','value'), Input('years','value')]
)
def update(genres, ratings, yr):
f = df.copy()
if genres: f = f[f['Genre'].isin(genres)]
if ratings: f = f[f['Rating'].isin(ratings)]
f = f[f['Year_of_Release'].between(yr[0], yr[1])]
cnt = f'Выбрано игр: {len(f)}'
area = px.area(f.groupby(['Year_of_Release', 'Platform']).size().reset_index(name='n'),
x='Year_of_Release', y='n', color='Platform')
sct = px.scatter(f, x='User_Score', y='Critic_Score', color='Genre')
return cnt, area, sct
if __name__ == '__main__':
app.run_server()Подводные камни
MIN(population)с одинаковыми минимумами —LIMIT 1вернёт один. Если нужны все —WHERE population = (SELECT MIN ...).- Pivot через CASE WHEN: если для одного
(ID, Name)несколько строк —MAXвыберет один. - Retention: по дням ровно (D1 =
install + 1 day)? Или интервал (D1 = «активен в первые 24h»)? Уточняйте. LEFT JOINобязателен — иначе пользователь без сессий выпадет, что искажает retention.User_Scoreстрокой в games.csv ('tbd', NaN) — нужна конвертация.- Dash callbacks: каждое изменение фильтра передаёт ВСЕ значения; не делайте отдельный callback на каждый фильтр.
Эталонный ответ
(1) ORDER + LIMIT 1 или MIN-subquery.
(2) Conditional aggregation MAX(CASE WHEN Name = 'X' THEN Val END).
(3) Pre-period installed_at после 2022-01-01, MAX(CASE) для D1/D3/D7, GROUP BY install month, AVG для retention.
(4) Plotly Dash с 3 фильтрами и обновлением 3 outputs.