File size: 12,185 Bytes
540fe64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import streamlit as st
import pandas as pd
from sqlalchemy import create_engine 
from PIL import Image

st.set_page_config(page_title="# Анализ данных StackOverflow")

st.markdown('# Анализ данных StackOverflow')

with st.expander("Описание проекта"):
    st.write("""
        Вы будете работать с базой данных StackOverflow — сервиса вопросов и ответов о программировании. 
    StackOverflow похож на социальную сеть — пользователи сервиса задают вопросы, отвечают на посты, оставляют комментарии и ставят оценки другим ответам.  
Вы будете работать с версией базы, где хранятся данные о постах за 2008 год, но в таблицах вы найдёте информацию и о более поздних оценках, которые эти посты получили.  

    Описание данных:

- Таблица badges:
    Хранит информацию о значках, которые присуждаются за разные достижения. Например, пользователь, правильно ответивший на большое количество вопросов про PostgreSQL, может получить значок postgresql. 
    - id	Идентификатор значка, первичный ключ таблицы
    - name	Название значка
    - user_id	Идентификатор пользователя, которому присвоили значок, внешний ключ, отсылающий к таблице users
    - creation_date	Дата присвоения значка
    
- Таблица post_types:
Содержит информацию о типе постов. Их может быть два:
    - Question — пост с вопросом;
    - Answer — пост с ответом.

    - id	Идентификатор поста, первичный ключ таблицы
    - type	Тип поста
- Таблица posts:
Содержит информацию о постах.

    - id	Идентификатор поста, первичный ключ таблицы
    - title	Заголовок поста
    - creation_date	Дата создания поста
    - favorites_count	Число, которое показывает, сколько раз пост добавили в «Закладки»
    - last_activity_date	Дата последнего действия в посте, например комментария
    - last_edit_date	Дата последнего изменения поста
    - user_id	Идентификатор пользователя, который создал пост, внешний ключ к таблице users
    - parent_id	Если пост написали в ответ на другую публикацию, в это поле попадёт идентификатор поста с вопросом
    - post_type_id	Идентификатор типа поста, внешний ключ к таблице post_types
    - score	Количество очков, которое набрал пост
    - views_count	Количество просмотров
- Таблица users:
Содержит информацию о пользователях.

    - id	Идентификатор пользователя, первичный ключ таблицы
    - creation_date	Дата регистрации пользователя
    - display_name	Имя пользователя
    - last_access_date	Дата последнего входа
    - location	Местоположение
    - reputation	Очки репутации, которые получают за хорошие вопросы и полезные ответы
    - views	Число просмотров профиля пользователя
- Таблица vote_types:
Содержит информацию о типах голосов. Голос — это метка, которую пользователи ставят посту. Типов бывает несколько: 
    - UpMod — такую отметку получают посты с вопросами или ответами, которые пользователи посчитали уместными и полезными.
    - DownMod — такую отметку получают посты, которые показались пользователям наименее полезными.
    - Close — такую метку ставят опытные пользователи сервиса, если заданный вопрос нужно доработать или он вообще не подходит для платформы.
    - Offensive — такую метку могут поставить, если пользователь ответил на вопрос в грубой и оскорбительной манере, например, указав на неопытность автора поста.
    - Spam — такую метку ставят в случае, если пост пользователя выглядит откровенной рекламой.

    - id	Идентификатор типа голоса, первичный ключ
    - name	Название метки
- Таблица votes:
    Содержит информацию о голосах за посты. 
    - id	Идентификатор голоса, первичный ключ
    - post_id	Идентификатор поста, внешний ключ к таблице posts
    - user_id	Идентификатор пользователя, который поставил посту голос, внешний ключ к таблице users
    - bounty_amount	Сумма вознаграждения, которое назначают, чтобы привлечь внимание к посту
    - vote_type_id	Идентификатор типа голоса, внешний ключ к таблице vote_types
    - creation_date	Дата назначения голоса
    """)



db_config = {
    'user': 'praktikum_student', # имя пользователя
    'pwd': 'Sdf4$2;d-d30pp', # пароль
    'host': 'rc1b-wcoijxj3yxfsf3fs.mdb.yandexcloud.net',
    'port': 6432, # порт подключения
    'db': 'data-analyst-advanced-sql' # название базы данных
    }  

connection_string = 'postgresql://{}:{}@{}:{}/{}'.format(
        db_config['user'],
        db_config['pwd'],
        db_config['host'],
        db_config['port'],
        db_config['db'],
    )
engine = create_engine(connection_string)

def query_db(query):
    return pd.read_sql_query(query, con=engine)

query_1 = '''SELECT date_trunc('month', creation_date) as month_date, sum(views_count) as total_views
FROM stackoverflow.posts
WHERE extract( YEAR from creation_date) = '2008'
GROUP BY month_date
ORDER BY total_views DESC
'''
query_2 = '''SELECT u.display_name, count(DISTINCT p.user_id)
FROM stackoverflow.users as u
JOIN stackoverflow.posts as p ON p.user_id = u.id
JOIN stackoverflow.post_types as pt ON pt.id = p.post_type_id
WHERE pt.type = 'Answer' AND
p.creation_date::date BETWEEN u.creation_date AND (u.creation_date::date + INTERVAL '1 month')
GROUP BY u.display_name
HAVING count(p.user_id)>100
ORDER BY u.display_name
'''
query_3 = '''WITH  dt as (SELECT u.id
FROM stackoverflow.posts as p
JOIN  stackoverflow.users as u ON p.user_id = u.id
WHERE DATE_TRUNC('month', u.creation_date) = '2008-09-01' AND
DATE_TRUNC('month', p.creation_date) = '2008-12-01')
SELECT date_trunc('month', p.creation_date)::date as month, count(p.id)
FROM stackoverflow.posts as p
WHERE p.user_id in (SELECT * FROM dt) AND
EXTRACT(YEAR FROM p.creation_date) = '2008'
GROUP BY month
ORDER BY month DESC
'''
query_4 = '''SELECT user_id, AVG(avg_daily)
FROM (SELECT DISTINCT user_id, date_trunc('day', creation_date)::date as t,
count(id) OVER (PARTITION BY user_id, date_trunc('day', creation_date)::date) as avg_daily,
count(id) OVER (PARTITION BY user_id, date_trunc('month', creation_date)::date) as cnt
FROM stackoverflow.posts
WHERE date_trunc('month', creation_date)::date = '2008-08-01') as dt
WHERE cnt>120
GROUP BY user_id
ORDER BY AVG(avg_daily)
'''

examples = {'Выводит общую сумму просмотров постов за каждый месяц 2008 года':query_1,
            'Выводит имена самых активных пользователей, которые в первый месяц после регистрации (включая день регистрации) дали больше 100 ответов':query_2,
            'Выводит количество постов за 2008 год по месяцам. Отбирает посты от пользователей, которые зарегистрировались в сентябре 2008 года и сделали хотя бы один пост в декабре того же года.':query_3,
            'Найдет среднее количество постов пользователей в день за август 2008 года. Отберет данные о пользователях, которые опубликовали больше 120 постов за август. Дни без публикаций не учитывает.':query_4,
            }
with st.expander("Схема быза данных"):
    image = Image.open('image/Frame.png')
    st.image(image)
    
with st.expander("Примеры SQL запросов"):
    
    query = st.selectbox('Выберете один из запросов:', ('Выводит общую сумму просмотров постов за каждый месяц 2008 года',
                                                        'Выводит имена самых активных пользователей, которые в первый месяц после регистрации (включая день регистрации) дали больше 100 ответов',
                                                        'Выводит количество постов за 2008 год по месяцам. Отбирает посты от пользователей, которые зарегистрировались в сентябре 2008 года и сделали хотя бы один пост в декабре того же года.',
                                                        'Найдет среднее количество постов пользователей в день за август 2008 года. Отберет данные о пользователях, которые опубликовали больше 120 постов за август. Дни без публикаций не учитывает.',
                                                        ))
    
    st.code(examples[query], language="sql", line_numbers=False)
    if st.button("Запуск запроса"):
        st.markdown('## Результат запроса:')
        st.write(query_db(examples[query]))



def submit():
    st.session_state.title = st.session_state.widget
    st.session_state.widget = ""

st.text_input("Введите ваш SQL запрос", key="widget", on_change=submit)

if 'title' not in st.session_state:
    st.session_state.title = ""    

title = st.session_state.title    



# st.write(title)       
# title = st.text_input('Введите ваш SQL запрос')
        
if title:
    st.markdown('## Ваш запрос:')
    st.code(title, language="sql", line_numbers=False)
    st.markdown('## Результат запроса:')
    try:
        st.write(query_db(title))
    except:
        'Запрос неверен, убедитесь в правильности запроса'