Skip to content

Sh-Nasib/Yandex_advanced_SQL

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 

Repository files navigation

StackOverflow

A er diagram datbase

Проект: Анализ StackOverflow с помощью SQL

Описание проекта:

Данный проект посвящен решению SQL-задач и анализу данных с использованием базы данных StackOverflow в системе управления базами данных PostgreSQL. StackOverflow - это популярный сервис вопросов и ответов, посвященный программированию и связанным с ним темам.

В рамках проекта будет использоваться версия базы данных, содержащая данные о постах, опубликованных на сайте в 2008 году и ранее. Проект состоит из двух основных частей, призванных продемонстрировать практическое применение SQL и аналитические возможности.

Первая часть включает в себя решение ряда задач в SQL-тренажёре. Эти задачи позволят вам применить на практике ваши знания SQL и научиться извлекать информацию из базы данных, отработать навыки написания запросов, манипуляции данными и использования различных функций и операторов SQL.

Вторая часть проекта носит аналитический характер. В этой части будет прадеставленн анализ данных StackOverflow, используя мощные инструменты SQL анализ данных, извлекать из них ценные сведения и делать выводы. Эта часть проекта позволит развить навыки анализа данных и научиться использовать SQL для получения ценной информации из больших наборов данных.

Проект предоставляет отличную возможность не только улучшить свои навыки SQL, но и получить практический опыт работы с реальной базой данных и углубить понимание анализа данных.

Цель проекта:

Продемонстрировать практическое применение SQL и аналитические возможности на реальном наборе данных. Проект направлен на решение SQL-задач и анализ данных из базы данных сервиса StackOverflow, посвященного программированию. Первая часть включает в себя решение задач в SQL-тренажёре, а вторая часть - это аналитический анализ данных с извлечением ценных сведений и выводов. Проект позволит улучшить навыки SQL, получить опыт работы с базой данных и углубить понимание анализа данных.

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

  • Таблица stackoverflow.badges

    Хранит информацию о значках, которые присуждаются за разные достижения. Например, пользователь, правильно ответивший на большое количество вопросов про PostgreSQL, может получить значок postgresql.

ПолеОписание
id Идентификатор значка, первичный ключ таблицы
name Название значка
user_id Идентификатор пользователя, которому присвоили значок, внешний ключ, отсылающий к таблице users
creation_date Дата присвоения значка

Таблица stackoverflow.post_types

Содержит информацию о типе постов. Их может быть два:

  • Question — пост с вопросом;
  • Answer — пост с ответом.
ПолеОписание
id Идентификатор типа поста, первичный ключ таблицы
type Тип поста

Таблица stackoverflow.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 Количество просмотров

Таблица stackoverflow.users

Содержит информацию о пользователях.

ПолеОписание
id Идентификатор пользователя, первичный ключ таблицы
creation_date Дата регистрации пользователя
display_name Имя пользователя
last_access_date Дата последнего входа
location Местоположение
reputation Очки репутации, которые получают за хорошие вопросы и полезные ответы
views Число просмотров профиля пользователя

Таблица stackoverflow.vote_types

Содержит информацию о типах голосов. Голос — это метка, которую пользователи ставят посту. Типов бывает несколько:

  • UpMod — такую отметку получают посты с вопросами или ответами, которые пользователи посчитали уместными и полезными.
  • DownMod — такую отметку получают посты, которые показались пользователям наименее полезными.
  • Close — такую метку ставят опытные пользователи сервиса, если заданный вопрос нужно доработать или он вообще не подходит для платформы.
  • Offensive — такую метку могут поставить, если пользователь ответил на вопрос в грубой и оскорбительной манере, например, указав на неопытность автора поста.
  • Spam — такую метку ставят в случае, если пост пользователя выглядит откровенной рекламой.
ПолеОписание
id Идентификатор типа голоса, первичный ключ
name Название метки

Таблица stackoverflow.votes

Содержит информацию о голосах за посты.

ПолеОписание
id Идентификатор голоса, первичный ключ
post_id Идентификатор поста, внешний ключ к таблице posts
user_id Идентификатор пользователя, который поставил посту голос, внешний ключ к таблице users
bounty_amount Сумма вознаграждения, которое назначают, чтобы привлечь внимание к посту
vote_type_id Идентификатор типа голоса, внешний ключ к таблице vote_types
creation_date Дата назначения голоса

Практическая часть

Запрос №1

Найдите количество вопросов, которые набрали больше 300 очков или как минимум 100 раз были добавлены в «Закладки».

Code
SELECT COUNT(id)
FROM stackoverflow.posts
WHERE (score > 300 OR favorites_count >= 100) AND post_type_id = 1;
Result

SQL2

Запрос №2

Сколько в среднем в день задавали вопросов с 1 по 18 ноября 2008 включительно? Результат округлите до целого числа.

Code
WITH 
questions AS (SELECT DISTINCT(CAST(DATE_TRUNC('day', p.creation_date) AS DATE)),
           COUNT(p.id) OVER (PARTITION BY CAST(DATE_TRUNC('day', p.creation_date) AS DATE))
    FROM stackoverflow.posts AS p
    LEFT JOIN stackoverflow.post_types AS pt ON p.post_type_id = pt.id 
    WHERE pt.type = 'Question' AND (CAST(DATE_TRUNC('day', p.creation_date) AS DATE) BETWEEN '2008.11.01' AND '2008.11.18'))
SELECT ROUND(AVG(count))::int 
FROM questions; 
Result

SQL2

Запрос №3

Сколько пользователей получили значки сразу в день регистрации? Выведите количество уникальных пользователей.

Code
SELECT COUNT(DISTINCT(u.id))
FROM stackoverflow.users u
LEFT JOIN stackoverflow.badges b ON u.id=b.user_id
WHERE DATE_TRUNC('day',u.creation_date)::DATE = DATE_TRUNC('day',b.creation_date)::DATE; 
Result

SQL2

Запрос №4

Сколько уникальных постов пользователя с именем Joel Coehoorn получили хотя бы один голос?

Code
WITH
name_id AS (SELECT id
    FROM stackoverflow.users
    WHERE display_name = 'Joel Coehoorn'),

post_votes AS (SELECT post_id
    FROM stackoverflow.votes
    GROUP BY post_id
    HAVING COUNT(*) > 0)

SELECT COUNT(DISTINCT p.id)
FROM stackoverflow.posts p
JOIN name_id ni ON p.user_id = ni.id
JOIN post_votes pv ON p.id = pv.post_id;
Result

SQL2

Запрос №5

Выгрузите все поля таблицы vote_types. Добавьте к таблице поле rank, в которое войдут номера записей в обратном порядке. Таблица должна быть отсортирована по полю id.

Code
SELECT *,
    RANK () OVER (ORDER BY id DESC) AS rank
FROM stackoverflow.vote_types    
ORDER BY id
LIMIT 5;
Result

SQL2

Запрос №6

Отберите 10 пользователей, которые поставили больше всего голосов типа Close. Отобразите таблицу из двух полей: идентификатором пользователя и количеством голосов. Отсортируйте данные сначала по убыванию количества голосов, потом по убыванию значения идентификатора пользователя.

Code
SELECT DISTINCT(user_id),
    COUNT(id) OVER(PARTITION BY user_id) AS vote
FROM stackoverflow.votes
WHERE vote_type_id = 6
ORDER BY vote DESC, user_id DESC
LIMIT 10;
Result

SQL2

Запрос №7

Отберите 10 пользователей по количеству значков, полученных в период с 15 ноября по 15 декабря 2008 года включительно.

Отобразите несколько полей:

  • идентификатор пользователя;
  • число значков;
  • место в рейтинге — чем больше значков, тем выше рейтинг.

Пользователям, которые набрали одинаковое количество значков, присвойте одно и то же место в рейтинге.

Отсортируйте записи по количеству значков по убыванию, а затем по возрастанию значения идентификатора пользователя.

Code
SELECT user_id,
    COUNT(id),
    DENSE_RANK() OVER(ORDER BY COUNT(id) DESC)
FROM stackoverflow.badges
WHERE creation_date::DATE BETWEEN '2008-11-15' AND '2008-12-15'
GROUP BY user_id
ORDER BY COUNT (id) DESC,user_id
LIMIT 10;
Result

SQL2

Запрос №8

Сколько в среднем очков получает пост каждого пользователя?

Сформируйте таблицу из следующих полей:

  • заголовок поста;

  • идентификатор пользователя;

  • число очков поста;

  • среднее число очков пользователя за пост, округлённое до целого числа.

Не учитывайте посты без заголовка, а также те, что набрали ноль очков.

Code
SELECT title,
    user_id,
    score,
    ROUND(AVG(score) OVER (PARTITION BY user_id))
FROM stackoverflow.posts
WHERE title IS NOT NULL AND score != 0
LIMIT 5;
Result

SQL2

Запрос №9

Отобразите заголовки постов, которые были написаны пользователями, получившими более 1000 значков. Посты без заголовков не должны попасть в список.

Code
WITH
users AS (SELECT user_id,
    COUNT(creation_date) count_badges
FROM stackoverflow.badges  b
GROUP BY user_id
HAVING COUNT(creation_date) > 1000)

SELECT title
FROM stackoverflow.posts p
WHERE user_id = (SELECT user_id FROM users) AND title IS NOT NULL;
Result

SQL2

Запрос №10

Напишите запрос, который выгрузит данные о пользователях из Канады (англ. Canada). Разделите пользователей на три группы в зависимости от количества просмотров их профилей:

  • пользователям с числом просмотров больше либо равным 350 присвойте группу 1;

  • пользователям с числом просмотров меньше 350, но больше либо равно 100 — группу 2;

  • пользователям с числом просмотров меньше 100 — группу 3.

Отобразите в итоговой таблице идентификатор пользователя, количество просмотров профиля и группу. Пользователи с количеством просмотров меньше либо равным нулю не должны войти в итоговую таблицу.

Code
SELECT id,
    views,
    CASE
        WHEN views < 100 THEN 3
        WHEN views >= 100 AND views < 350 THEN 2
        ELSE 1
    END AS group 
FROM stackoverflow.users 
WHERE location LIKE '%Canada%' AND views > 0
LIMIT 5;
Result

SQL2

Запрос №11

Дополните предыдущий запрос. Отобразите лидеров каждой группы — пользователей, которые набрали максимальное число просмотров в своей группе. Выведите поля с идентификатором пользователя, группой и количеством просмотров. Отсортируйте таблицу по убыванию просмотров, а затем по возрастанию значения идентификатора.

Code
WITH
data AS (SELECT id,
    views,
    CASE
        WHEN views < 100 THEN 3
        WHEN views >= 100 AND views < 350 THEN 2
        ELSE 1
    END AS group_user
FROM stackoverflow.users 
WHERE location LIKE '%Canada%' AND views > 0)

SELECT id, group_user, views
FROM (SELECT id,
                 views,
                 group_user,
                 MAX(views) OVER (PARTITION BY group_user ORDER BY views DESC) AS max_views
            FROM data) AS dat
WHERE max_views = views
ORDER BY views DESC, id;
Result

SQL2

Запрос №12

Посчитайте ежедневный прирост новых пользователей в ноябре 2008 года. Сформируйте таблицу с полями:

  • номер дня;

  • число пользователей, зарегистрированных в этот день;

  • сумму пользователей с накоплением.

Code
SELECT EXTRACT(DAY FROM day),
    count_user,
    SUM(count_user) OVER(ORDER BY day)
FROM (SELECT DISTINCT(creation_date::DATE) AS day,
    COUNT(id) OVER(PARTITION BY creation_date::DATE) AS count_user
FROM stackoverflow.users
WHERE creation_date::DATE BETWEEN '2008-11-01' AND '2008-11-30') AS dat;
Result

SQL2

Запрос №13

Для каждого пользователя, который написал хотя бы один пост, найдите интервал между регистрацией и временем создания первого поста. Отобразите:

  • идентификатор пользователя;

  • разницу во времени между регистрацией и первым постом.

Code
SELECT user_id,
    post_date-creation_date
FROM (SELECT DISTINCT(p.user_id) user_id,
    MIN(p.creation_date) OVER(PARTITION BY p.user_id) post_date,
    u.creation_date creation_date
FROM stackoverflow.posts p
JOIN stackoverflow.users u ON p.user_id=u.id) dat;
Result

SQL2

Аналитическая часть

Запрос №1

Выведите общую сумму просмотров у постов, опубликованных в каждый месяц 2008 года. Если данных за какой-либо месяц в базе нет, такой месяц можно пропустить. Результат отсортируйте по убыванию общего количества просмотров.

Code
SELECT DISTINCT(DATE_TRUNC('month',creation_date)::DATE),
    SUM(views_count) OVER(PARTITION BY DATE_TRUNC('month',creation_date)::DATE)
FROM stackoverflow.posts
WHERE EXTRACT(YEAR FROM creation_date) = 2008
ORDER BY SUM(views_count) OVER(PARTITION BY DATE_TRUNC('month',creation_date)::DATE) DESC
LIMIT 5;
Result

SQL2

Запрос №2

Выведите имена самых активных пользователей, которые в первый месяц после регистрации (включая день регистрации) дали больше 100 ответов. Вопросы, которые задавали пользователи, не учитывайте. Для каждого имени пользователя выведите количество уникальных значений user_id. Отсортируйте результат по полю с именами в лексикографическом порядке.

Code
SELECT u.display_name,
       COUNT(DISTINCT p.user_id)
FROM stackoverflow.posts AS p
JOIN stackoverflow.users AS u 
ON p.user_id=u.id
WHERE p.creation_date::date BETWEEN u.creation_date::date AND (u.creation_date::date + INTERVAL '1 month') 
      AND post_type_id = 2
GROUP BY u.display_name
HAVING COUNT(p.id) > 100
ORDER BY u.display_name
LIMIT 5;
Result

SQL2

Запрос №3

Выведите количество постов за 2008 год по месяцам. Отберите посты от пользователей, которые зарегистрировались в сентябре 2008 года и сделали хотя бы один пост в декабре того же года. Отсортируйте таблицу по значению месяца по убыванию.

Code
WITH
use AS (SELECT id
FROM stackoverflow.users
WHERE DATE_TRUNC('month',creation_date)::DATE = '2008-09-01'),

use_id AS (SELECT DISTINCT(p.user_id)
FROM stackoverflow.posts p
JOIN use ON p.user_id=use.id
WHERE DATE_TRUNC('month',p.creation_date)::DATE = '2008-12-01')

SELECT DISTINCT(DATE_TRUNC('month',creation_date)::DATE),
    COUNT(id) OVER(PARTITION BY DATE_TRUNC('month',creation_date)::DATE)
FROM stackoverflow.posts p
JOIN use_id ON p.user_id=use_id.user_id
WHERE DATE_TRUNC('year',p.creation_date)::DATE = '2008-01-01'
ORDER BY DATE_TRUNC('month',creation_date)::DATE DESC;
Result

SQL2

Запрос №4

Используя данные о постах, выведите несколько полей:

  • идентификатор пользователя, который написал пост;

  • дата создания поста;

  • количество просмотров у текущего поста;

  • сумма просмотров постов автора с накоплением.

Данные в таблице должны быть отсортированы по возрастанию идентификаторов пользователей, а данные об одном и том же пользователе — по возрастанию даты создания поста.

Code
SELECT user_id,
    creation_date,
    views_count,
    SUM(views_count) OVER(PARTITION BY user_id ORDER BY creation_date)
FROM stackoverflow.posts
ORDER BY user_id,creation_date
LIMIT 5;
Result

SQL2

Запрос №5

Сколько в среднем дней в период с 1 по 7 декабря 2008 года включительно пользователи взаимодействовали с платформой? Для каждого пользователя отберите дни, в которые он или она опубликовали хотя бы один пост. Нужно получить одно целое число — не забудьте округлить результат.

Code
WITH 
post AS (SELECT user_id,
    COUNT(DISTINCT(DATE_TRUNC('day', creation_date)::date))
FROM stackoverflow.posts
WHERE creation_date::date BETWEEN '2008-12-01' AND '2008-12-07'
GROUP BY user_id)

SELECT ROUND(AVG(count))
FROM post;
Result

SQL2

Запрос №6

На сколько процентов менялось количество постов ежемесячно с 1 сентября по 31 декабря 2008 года? Отобразите таблицу со следующими полями:

  • Номер месяца.

  • Количество постов за месяц.

  • Процент, который показывает, насколько изменилось количество постов в текущем месяце по сравнению с предыдущим.

Если постов стало меньше, значение процента должно быть отрицательным, если больше — положительным. Округлите значение процента до двух знаков после запятой.

Напомним, что при делении одного целого числа на другое в PostgreSQL в результате получится целое число, округлённое до ближайшего целого вниз. Чтобы этого избежать, переведите делимое в тип numeric.

Code
WITH
dat AS (SELECT DISTINCT(EXTRACT(MONTH FROM creation_date)) month_creat,
    COUNT(id) OVER(PARTITION BY EXTRACT(MONTH FROM creation_date)) count_month
FROM stackoverflow.posts p
WHERE creation_date::DATE BETWEEN '2008-09-01' AND '2008-12-31'),

lag_dat AS (SELECT month_creat,
    count_month,
    LAG(count_month) OVER() lag
FROM dat)

SELECT month_creat,
    count_month,
    ROUND((count_month::numeric/lag-1)*100,2)
FROM lag_dat;
Result

SQL2

Запрос №6

Найдите пользователя, который опубликовал больше всего постов за всё время с момента регистрации. Выведите данные его активности за октябрь 2008 года в таком виде:

  • номер недели;

  • дата и время последнего поста, опубликованного на этой неделе.

Code
WITH
max_post AS (SELECT DISTINCT(user_id),
    COUNT(id) OVER(PARTITION BY user_id)
FROM stackoverflow.posts
ORDER BY COUNT(id) OVER(PARTITION BY user_id) DESC
LIMIT 1)

SELECT EXTRACT(WEEK FROM p.creation_date) week_creation,
       MAX(p.creation_date) creation_date
FROM  max_post m
JOIN stackoverflow.posts p ON m.user_id=p.user_id
WHERE DATE_TRUNC('month', p.creation_date)::date = '2008-10-01'
GROUP BY EXTRACT(WEEK FROM p.creation_date);
Result

SQL2

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published