diff --git a/ebelykh/postgresql/JOIN/JOIN.sql b/ebelykh/postgresql/JOIN/JOIN.sql new file mode 100644 index 0000000..ec94940 --- /dev/null +++ b/ebelykh/postgresql/JOIN/JOIN.sql @@ -0,0 +1,20 @@ +--Задача 1068 +SELECT p.product_name, s.year, s.price +FROM Sales s +JOIN Product p +ON s.product_id = p.product_id; + +--Задача 1378 +SELECT EmployeeUNI.unique_id, + Employees.name +FROM Employees +LEFT JOIN EmployeeUNI +ON Employees.id = EmployeeUNI.id; + +--Задача 577 +SELECT e.name, b.bonus +FROM Employee e +LEFT JOIN Bonus b +ON e.empId = b.empId +WHERE b.bonus < 1000 + OR b.bonus IS NULL; \ No newline at end of file diff --git a/ebelykh/postgresql/Оконные функции/task_1.png b/ebelykh/postgresql/Оконные функции/task_1.png new file mode 100644 index 0000000..c68655d Binary files /dev/null and b/ebelykh/postgresql/Оконные функции/task_1.png differ diff --git a/ebelykh/postgresql/Оконные функции/task_180.1 .png b/ebelykh/postgresql/Оконные функции/task_180.1 .png new file mode 100644 index 0000000..35b3678 Binary files /dev/null and b/ebelykh/postgresql/Оконные функции/task_180.1 .png differ diff --git a/ebelykh/postgresql/Оконные функции/task_180.2 .png b/ebelykh/postgresql/Оконные функции/task_180.2 .png new file mode 100644 index 0000000..6c07177 Binary files /dev/null and b/ebelykh/postgresql/Оконные функции/task_180.2 .png differ diff --git a/ebelykh/postgresql/Оконные функции/task_2.png b/ebelykh/postgresql/Оконные функции/task_2.png new file mode 100644 index 0000000..26271a3 Binary files /dev/null and b/ebelykh/postgresql/Оконные функции/task_2.png differ diff --git a/ebelykh/postgresql/Оконные функции/task_3.png b/ebelykh/postgresql/Оконные функции/task_3.png new file mode 100644 index 0000000..e9a5fa0 Binary files /dev/null and b/ebelykh/postgresql/Оконные функции/task_3.png differ diff --git a/ebelykh/postgresql/Оконные функции/task_4.png b/ebelykh/postgresql/Оконные функции/task_4.png new file mode 100644 index 0000000..545e9a6 Binary files /dev/null and b/ebelykh/postgresql/Оконные функции/task_4.png differ diff --git a/ebelykh/postgresql/ПЭТ проект/Script.sql b/ebelykh/postgresql/ПЭТ проект/Script.sql new file mode 100644 index 0000000..25727d1 --- /dev/null +++ b/ebelykh/postgresql/ПЭТ проект/Script.sql @@ -0,0 +1,233 @@ +CREATE TABLE users ( + id INT PRIMARY KEY, + name TEXT, + age INT, + email TEXT, + registration_date DATE +); + +INSERT INTO users VALUES +(1, 'Alice', 25, 'alice@mail.com', '2023-01-10'), +(2, 'Bob', 30, 'bob@gmail.com', '2023-02-05'), +(3, 'Charlie', 22, 'charlie@mail.com', '2023-02-20'), +(4, 'Diana', 28, 'diana@mail.com', '2023-03-01'), +(5, 'Ethan', 35, 'ethan@gmail.com', '2023-03-10'); + +SELECT * FROM users ORDER BY id; + +CREATE TABLE courses ( + id INT PRIMARY KEY, + title TEXT, + category TEXT, + created_at DATE +); + +INSERT INTO courses VALUES +(1, 'SQL для начинающих', 'data', '2023-01-01'), +(2, 'Python для анализа данных', 'programming', '2023-01-15'), +(3, 'BI с нуля', 'business', '2023-03-01'); + + +SELECT * FROM courses ORDER BY id; + + +CREATE TABLE lessons ( + id INT PRIMARY KEY, + course_id INT, + title TEXT, + duration_min INT, + FOREIGN KEY (course_id) REFERENCES courses(id) +); + +INSERT INTO lessons VALUES +(1, 1, 'SELECT и FROM', 10), +(2, 1, 'JOIN', 15), +(3, 2, 'Pandas', 20), +(4, 3, 'Основы BI', 12), +(5, 3, 'Метрики и дашборды', 18); + +SELECT * FROM lessons ORDER BY id; + + +CREATE TABLE enrollments ( + id INT PRIMARY KEY, + user_id INT, + course_id INT, + enrolled_at DATE, + FOREIGN KEY (user_id) REFERENCES users(id), + FOREIGN KEY (course_id) REFERENCES courses(id) +); + +INSERT INTO enrollments VALUES +(1, 1, 1, '2023-01-15'), +(2, 1, 2, '2023-02-01'), +(3, 2, 1, '2023-01-20'), +(4, 3, 2, '2023-03-05'), +(5, 4, 3, '2023-04-01'); + +SELECT * FROM enrollments ORDER BY id; + +CREATE TABLE lesson_views ( + id INT PRIMARY KEY, + user_id INT, + lesson_id INT, + viewed_at TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id), + FOREIGN KEY (lesson_id) REFERENCES lessons(id) +); + +INSERT INTO lesson_views VALUES +(1, 1, 1, '2023-01-16 10:00:00'), +(2, 1, 2, '2023-01-16 10:15:00'), +(3, 2, 1, '2023-01-21 09:00:00'), +(4, 3, 3, '2023-03-06 12:00:00'), +(5, 4, 4, '2023-04-02 10:00:00'), +(6, 4, 5, '2023-04-03 10:00:00'); + +SELECT * FROM lesson_views ORDER BY id; + +--Создаем materialized view c названием user_activity_summary + +DROP MATERIALIZED VIEW IF EXISTS user_activity_summary; + + +CREATE MATERIALIZED VIEW user_activity_summary AS +WITH +enr AS ( + SELECT + user_id, + COUNT(*) AS enrollment_count + FROM enrollments + GROUP BY user_id +), +views AS ( + SELECT + user_id, + COUNT(DISTINCT lesson_id) AS viewed_lessons_count, + MIN(viewed_at) AS first_view, + MAX(viewed_at) AS last_view + FROM lesson_views + GROUP BY user_id +), +possible AS ( + SELECT + e.user_id, + COUNT(l.id) AS possible_lessons + FROM enrollments e + JOIN lessons l ON l.course_id = e.course_id + GROUP BY e.user_id +) +SELECT + u.id AS user_id, + u.name, + enr.enrollment_count, + COALESCE(views.viewed_lessons_count, 0) AS viewed_lessons_count, + views.last_view, + views.first_view, + ROUND( + COALESCE(views.viewed_lessons_count, 0)::numeric + / possible.possible_lessons * 100, + 2 + ) || '%' AS engagement_rate +FROM users u +JOIN enr ON enr.user_id = u.id +JOIN possible ON possible.user_id = u.id +LEFT JOIN views ON views.user_id = u.id +ORDER BY u.id; + +--Проверка +SELECT * FROM user_activity_summary ORDER BY user_id; + + +--Создаем materialized view c названием course_summary + +DROP MATERIALIZED VIEW IF EXISTS course_summary; + + +CREATE MATERIALIZED VIEW course_summary AS +WITH +-- 1) сколько уроков в каждом курсе +lessons_cnt AS ( + SELECT + course_id, + COUNT(*) AS lessons_count + FROM lessons + GROUP BY course_id +), + +-- 2) сколько уникальных пользователей записано на курс +users_cnt AS ( + SELECT + course_id, + COUNT(DISTINCT user_id) AS unique_users + FROM enrollments + GROUP BY course_id +), + +-- 3) просмотры по курсу (через lessons -> course_id) +views_cnt AS ( + SELECT + l.course_id, + COUNT(lv.id) AS total_views, + MIN(lv.viewed_at) AS first_viewed_at, + MAX(lv.viewed_at) AS last_viewed_at + FROM lessons l + LEFT JOIN lesson_views lv ON lv.lesson_id = l.id + GROUP BY l.course_id +) + +SELECT + c.id AS course_id, + c.title AS course_title, + + COALESCE(u.unique_users, 0) AS unique_users, + COALESCE(ls.lessons_count, 0) AS lessons_count, + COALESCE(v.total_views, 0) AS total_views, + + ROUND( + COALESCE(v.total_views, 0)::numeric / NULLIF(COALESCE(u.unique_users, 0), 0), + 2 + ) AS avg_views_per_user, + + v.first_viewed_at, + v.last_viewed_at +FROM courses c +LEFT JOIN users_cnt u ON u.course_id = c.id +LEFT JOIN lessons_cnt ls ON ls.course_id = c.id +LEFT JOIN views_cnt v ON v.course_id = c.id +ORDER BY c.id; + +SELECT * FROM course_summary ORDER BY course_id; + +--Создаем materialized view c названием platform_summary + +DROP MATERIALIZED VIEW IF EXISTS platform_summary; + +CREATE MATERIALIZED VIEW platform_summary AS +SELECT + (SELECT COUNT(*) FROM users) AS total_users, + (SELECT COUNT(*) FROM courses) AS total_courses, + (SELECT COUNT(*) FROM lessons) AS total_lessons, + + (SELECT COUNT(DISTINCT user_id) FROM lesson_views) AS users_with_views, + + ROUND( + (SELECT COUNT(*) FROM lessons)::numeric + / (SELECT COUNT(*) FROM courses), + 2 + ) AS avg_lessons_per_course, + + ROUND( + (SELECT COUNT(*) FROM lesson_views)::numeric + / (SELECT COUNT(*) FROM lessons), + 2 + ) AS avg_views_per_lesson; + + SELECT * FROM platform_summary; + +--Доп. задание: EXPLAIN +EXPLAIN SELECT * FROM user_activity_summary; +EXPLAIN SELECT * FROM course_summary; + + + \ No newline at end of file diff --git a/ebelykh/postgresql/Подзапросы и СТЕ/Task_01174.png b/ebelykh/postgresql/Подзапросы и СТЕ/Task_01174.png new file mode 100644 index 0000000..1591517 Binary files /dev/null and b/ebelykh/postgresql/Подзапросы и СТЕ/Task_01174.png differ diff --git a/ebelykh/postgresql/Подзапросы и СТЕ/Task_01327.png b/ebelykh/postgresql/Подзапросы и СТЕ/Task_01327.png new file mode 100644 index 0000000..a1da532 Binary files /dev/null and b/ebelykh/postgresql/Подзапросы и СТЕ/Task_01327.png differ diff --git a/ebelykh/postgresql/Подзапросы и СТЕ/Task_0176.png b/ebelykh/postgresql/Подзапросы и СТЕ/Task_0176.png new file mode 100644 index 0000000..d9d5cb5 Binary files /dev/null and b/ebelykh/postgresql/Подзапросы и СТЕ/Task_0176.png differ diff --git a/ebelykh/postgresql/Подзапросы и СТЕ/Task_0196.png b/ebelykh/postgresql/Подзапросы и СТЕ/Task_0196.png new file mode 100644 index 0000000..c46c7ad Binary files /dev/null and b/ebelykh/postgresql/Подзапросы и СТЕ/Task_0196.png differ diff --git a/ebelykh/postgresql/Подзапросы и СТЕ/Task_01978.png b/ebelykh/postgresql/Подзапросы и СТЕ/Task_01978.png new file mode 100644 index 0000000..24108d4 Binary files /dev/null and b/ebelykh/postgresql/Подзапросы и СТЕ/Task_01978.png differ diff --git a/ebelykh/postgresql/Подзапросы и СТЕ/Task_0602.png b/ebelykh/postgresql/Подзапросы и СТЕ/Task_0602.png new file mode 100644 index 0000000..f9885ed Binary files /dev/null and b/ebelykh/postgresql/Подзапросы и СТЕ/Task_0602.png differ diff --git a/ebelykh/postgresql/агрегации и группировки/агрегации.sql b/ebelykh/postgresql/агрегации и группировки/агрегации.sql new file mode 100644 index 0000000..7d5bf7d --- /dev/null +++ b/ebelykh/postgresql/агрегации и группировки/агрегации.sql @@ -0,0 +1,72 @@ +--Задача 1 +В варианте А: WHERE фильтрует товары и убирает те, которые не в наличии, потом эти товары(строки)участвуют в группировке, в варианте В - HAVING фильтрует уже сгруппированные данные(категории) + +--Задача 2356 +SELECT teacher_id, + COUNT(DISTINCT subject_id) AS cnt +FROM teacher +GROUP BY teacher_id; + +--Задача 1581 +SELECT customer_id, + COUNT(v.visit_id) AS count_no_trans +FROM visits v +LEFT JOIN transactions t +ON v.visit_id = t.visit_id +WHERE t.transaction_id IS NULL +GROUP BY customer_id; + +--Задача 1141 +SELECT activity_date AS day, + COUNT(DISTINCT user_id) AS active_users +FROM Activity +WHERE activity_date BETWEEN '2019-06-28' AND '2019-07-27' +GROUP BY activity_date; + +--Задача 596 +SELECT class +FROM Courses +GROUP BY class +HAVING COUNT(student) >= 5; + +--Задача 1075 +SELECT project_id, + ROUND(AVG(experience_years), 2) AS average_years +FROM Project p +JOIN Employee e +ON p.employee_id = e.employee_id +GROUP BY project_id; + +--Задача 1729 +SELECT user_id, + COUNT (follower_id) AS followers_count +FROM followers +GROUP BY user_id +ORDER BY user_id; + +--Задача 1633 +SELECT + r.contest_id, + ROUND( + COUNT(r.user_id) * 100.0 / (SELECT COUNT(*) FROM Users), + 2 + ) AS percentage +FROM Register r +GROUP BY r.contest_id +ORDER BY percentage DESC, r.contest_id ASC; + +--Задача 1251 +SELECT + p.product_id, + COALESCE( + ROUND( + SUM(u.units * p.price) * 1.0 / NULLIF(SUM(u.units), 0), + 2 + ), + 0 + ) AS average_price +FROM Prices p +LEFT JOIN UnitsSold u + ON p.product_id = u.product_id + AND u.purchase_date BETWEEN p.start_date AND p.end_date +GROUP BY p.product_id; \ No newline at end of file diff --git a/ebelykh/postgresql/базовый SQL/Select.sql b/ebelykh/postgresql/базовый SQL/Select.sql new file mode 100644 index 0000000..2ccfb16 --- /dev/null +++ b/ebelykh/postgresql/базовый SQL/Select.sql @@ -0,0 +1,43 @@ +--Задача 1757 +SELECT product_id +FROM Products +WHERE low_fats = 'Y' AND recyclable = 'Y'; + +--Задача 584 +SELECT name +FROM Customer +WHERE referee_id!= 2 OR referee_id IS NULL; + +--Задача 595 +SELECT name, population, area +FROM World +WHERE area >= 3000000 + OR population >= 25000000; + +--Задача 1148 +SELECT DISTINCT author_id AS id +FROM Views +WHERE author_id = viewer_id +ORDER BY id; + +--Задача 1683 +SELECT tweet_id +FROM Tweets +WHERE CHAR_LENGTH(content) > 15; + +--Задача 620 +SELECT id, movie, description, rating +FROM Cinema +WHERE id % 2 = 1 + AND description != 'boring' +ORDER BY rating DESC; + +--Задача 1667 +SELECT + user_id, + CONCAT( + UPPER(SUBSTR(name, 1, 1)), + LOWER(SUBSTR(name, 2)) + ) AS name +FROM Users +ORDER BY user_id; diff --git a/ebelykh/postgresql/оконные функции/task_1.png b/ebelykh/postgresql/оконные функции/task_1.png new file mode 100644 index 0000000..c68655d Binary files /dev/null and b/ebelykh/postgresql/оконные функции/task_1.png differ diff --git a/ebelykh/postgresql/оконные функции/task_180.1 .png b/ebelykh/postgresql/оконные функции/task_180.1 .png new file mode 100644 index 0000000..35b3678 Binary files /dev/null and b/ebelykh/postgresql/оконные функции/task_180.1 .png differ diff --git a/ebelykh/postgresql/оконные функции/task_180.2 .png b/ebelykh/postgresql/оконные функции/task_180.2 .png new file mode 100644 index 0000000..6c07177 Binary files /dev/null and b/ebelykh/postgresql/оконные функции/task_180.2 .png differ diff --git a/ebelykh/postgresql/оконные функции/task_2.png b/ebelykh/postgresql/оконные функции/task_2.png new file mode 100644 index 0000000..26271a3 Binary files /dev/null and b/ebelykh/postgresql/оконные функции/task_2.png differ diff --git a/ebelykh/postgresql/оконные функции/task_3.png b/ebelykh/postgresql/оконные функции/task_3.png new file mode 100644 index 0000000..e9a5fa0 Binary files /dev/null and b/ebelykh/postgresql/оконные функции/task_3.png differ diff --git a/ebelykh/postgresql/оконные функции/task_4.png b/ebelykh/postgresql/оконные функции/task_4.png new file mode 100644 index 0000000..545e9a6 Binary files /dev/null and b/ebelykh/postgresql/оконные функции/task_4.png differ diff --git a/ebelykh/postgresql/основы SQL/Script.sql b/ebelykh/postgresql/основы SQL/Script.sql new file mode 100644 index 0000000..f698b99 --- /dev/null +++ b/ebelykh/postgresql/основы SQL/Script.sql @@ -0,0 +1,33 @@ +--Задача 1 + CREATE TABLE products_extended ( + id INT PRIMARY KEY, + name VARCHAR(100) NOT NULL, + category VARCHAR(50), + price DECIMAL(6,2), + in_stock BOOLEAN DEFAULT true, + email_support VARCHAR +); + + +--Задача 2 Вариант с DEFAULT (in_stock не указываем) +INSERT INTO products_extended (id, name, category, price, email_support) +VALUES +(1, 'Mi Band 7', 'smartwatch', 49.00, 'miband@xiaomi.com'), +(2, 'Surface Pro', 'tablet', 1299.00, 'surface@microsoft.com'); + +--Задача 3 +ALTER TABLE products_extended +ADD COLUMN rating DECIMAL(3,2), +DROP COLUMN email_support; + +--Задача 4 +UPDATE products_extended +SET price = price * 1.1 +WHERE name = 'Mi Band 7'; + +--Задача 5(удаляет данные/таблицу) +TRUNCATE TABLE products_extended; +DROP TABLE products_extended; + + + diff --git a/ebelykh/postgresql/фильтрация/Script.sql b/ebelykh/postgresql/фильтрация/Script.sql new file mode 100644 index 0000000..c666713 --- /dev/null +++ b/ebelykh/postgresql/фильтрация/Script.sql @@ -0,0 +1,54 @@ +SELECT + name, + category, + price, + price * 1.10 AS price_with_markup, + price * 1.20 AS price_with_vat, + COALESCE(email_support, 'нет почты') AS status +FROM products_extended +WHERE in_stock = true + AND category NOT IN ('smartwatch', 'ebook_reader') + AND price BETWEEN 300 AND 1300; + +SELECT + name, + category, + email_support, + price * 1.25 AS price_25, + price > 1000 AS premium +FROM products_extended +WHERE (price < 150 OR price > 1200) + AND email_support IS NOT NULL; + +SELECT + id, + name, + category, + price +FROM products_extended +WHERE category IN ('smartphone', 'laptop', 'tablet') + AND name NOT LIKE '%i%' + AND price BETWEEN 500 AND 1300 +ORDER BY id; + +SELECT + name, + category, + price, + 'нет поддержки' AS comment +FROM products_extended +WHERE in_stock = true + AND email_support IS NULL + AND price < 800; + +SELECT + name, + category, + price, + price > 1000 AS premium +FROM products_extended +WHERE (name LIKE '%Pro' OR name LIKE '%X%') + AND in_stock = true + AND price > 700; + + diff --git a/ebelykh/postgresql/функции/функции.sql b/ebelykh/postgresql/функции/функции.sql new file mode 100644 index 0000000..eb1a659 --- /dev/null +++ b/ebelykh/postgresql/функции/функции.sql @@ -0,0 +1,20 @@ +--Задача 1211 +SELECT + query_name, + ROUND(AVG(rating * 1.0 / position), 2) AS quality, + ROUND(AVG(CASE WHEN rating < 3 THEN 1 ELSE 0 END) * 100,2) AS poor_query_percentage +FROM Queries +GROUP BY query_name; + +--Задача 1193 +SELECT + TO_CHAR(trans_date, 'YYYY-MM') AS month, + country, + COUNT(*) AS trans_count, + SUM(CASE WHEN state = 'approved' THEN 1 ELSE 0 END) AS approved_count, + SUM(amount) AS trans_total_amount, + SUM(CASE WHEN state = 'approved' THEN amount ELSE 0 END) AS approved_total_amount +FROM Transactions +GROUP BY + TO_CHAR(trans_date, 'YYYY-MM'), + country; \ No newline at end of file