From 1fad7c39d75141a59a188dd639b5ed154b5a78b3 Mon Sep 17 00:00:00 2001 From: Dmitriy Rusanov <99138978+DimaRus05@users.noreply.github.com> Date: Mon, 6 Oct 2025 14:51:17 +0300 Subject: [PATCH] Add files via upload --- hw4.sql | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 hw4.sql diff --git a/hw4.sql b/hw4.sql new file mode 100644 index 0000000..38cd212 --- /dev/null +++ b/hw4.sql @@ -0,0 +1,214 @@ +--Домашняя работа 4. Использование подзапросов и табличных выражений +--1. Выведите самые дорогие продукты в каждой категории. Детали должны присутствовать! +-- Решите данную задачу с использованием: +--a. вложенного подзапроса + +SELECT + p.productname, + p.categoryid, + p.unitprice +FROM "Production"."Products" p +JOIN ( + SELECT + categoryid, + MAX(unitprice) AS max_price + FROM "Production"."Products" + GROUP BY categoryid +) AS max_prices ON p.categoryid = max_prices.categoryid AND p.unitprice = max_prices.max_price; + +--b. коррелированного подзапроса + +SELECT + p1.productname, + p1.categoryid, + p1.unitprice +FROM "Production"."Products" p1 +WHERE p1.unitprice = ( + SELECT MAX(p2.unitprice) + FROM "Production"."Products" p2 + WHERE p2.categoryid = p1.categoryid +); + +--c. оконной функции + +SELECT + productname, + categoryid, + unitprice +FROM ( + SELECT + productname, + categoryid, + unitprice, + RANK() OVER (PARTITION BY categoryid ORDER BY unitprice DESC) AS price_rank + FROM "Production"."Products" +) ranked_products +WHERE price_rank = 1; + +--2. Выведите код заказчика, год заказа, ранг по каждому заказчику в каждом году в соответствии с общей стоимостью заказа (OrderTotal) и стоимость заказа. +-- В выборке должны присутствовать только записи с рангом 1 и 2. Воспользуйтесь представлением public."OrderValues" + +SELECT * +FROM ( + SELECT + custid, + EXTRACT(YEAR FROM orderdate) AS "Year", + RANK() OVER (PARTITION BY custid, EXTRACT(YEAR FROM orderdate) ORDER BY "OrderTotal" DESC) AS "Rank", + "OrderTotal" + FROM public."OrderValues" +) ranked_orders +WHERE "Rank" <= 2 +ORDER BY custid, "Rank"; + +--3. Выведите информацию о заказчиках, за исключением тех, кто купил менее 30 наименований продуктов. + +SELECT DISTINCT + c.custid, + c.companyname, + c.contacttitle +FROM "Sales"."Customers" c +WHERE c.custid IN ( + SELECT o.custid + FROM "Sales"."Orders" o + JOIN "Sales"."OrderDetails" od ON o.orderid = od.orderid + GROUP BY o.custid + HAVING COUNT(DISTINCT od.productid) >= 30 +) +ORDER BY c.custid; + +--4. Используя запрос к таблице Продуктов сформируйте выборку следующего вида: +-- Для формирования значений в столбцах Category Name и AveragePrice (средняя цена продуктов по категории) используйте коррелированные подзапросы. +-- Выборка должна включать только те товары, цена которых выше средней по категории. + +SELECT + p.productname, + p.unitprice, + (SELECT c.categoryname + FROM "Production"."Categories" c + WHERE c.categoryid = p.categoryid) AS CategoryName, + (SELECT (AVG((p2.unitprice)::numeric(10, 2)))::money + FROM "Production"."Products" p2 + WHERE p2.categoryid = p.categoryid) AS AveragePrice +FROM "Production"."Products" p +WHERE p.unitprice > ( + SELECT AVG((p3.unitprice)::numeric(10, 2))::money + FROM "Production"."Products" p3 + WHERE p3.categoryid = p.categoryid +); + +--5. Выведите список товаров, цена которых выше средней цены по категории. +--Для формирования столбцов categoryname и avg_unitprice используйте коррелированные подзапросы + +SELECT + p.productname, + p.unitprice, + (SELECT c.categoryname + FROM "Production"."Categories" c + WHERE c.categoryid = p.categoryid) AS CategoryName, + (SELECT AVG((p2.unitprice)::numeric(10, 2))::money + FROM "Production"."Products" p2 + WHERE p2.categoryid = p.categoryid) AS AveragePrice +FROM "Production"."Products" p +WHERE p.unitprice > ( + SELECT AVG((p3.unitprice)::numeric(10, 2))::money + FROM "Production"."Products" p3 + WHERE p3.categoryid = p.categoryid +); + +--6. Сформируйте выборку следующего вида: +-- Выборка должна содержать только те записи, в которых стоимость заказов, сделанных конкретным заказчиком за самый первый год, +-- когда он делал заказы (first-year) не превышает стоимость заказов за последующие года. +-- То есть, разница (diff) между стоимостью заказов текущего года и заказов за первый год меньше нуля. + +SELECT + yt.custid, + c.companyname, + yt.year, + yt.ord_total::money AS ord_total, + fyt.first_year_total::money AS "first-year", + (CASE + WHEN (yt.ord_total - fyt.first_year_total) < 0 + THEN -1 * (yt.ord_total - fyt.first_year_total) + ELSE (yt.ord_total - fyt.first_year_total) + END)::money AS diff +FROM ( + SELECT + o.custid, + EXTRACT(YEAR FROM o.orderdate) AS year, + SUM(ov."OrderTotal") AS ord_total + FROM "Sales"."Orders" o + JOIN public."OrderValues" ov ON o.orderid = ov.orderid + GROUP BY o.custid, EXTRACT(YEAR FROM o.orderdate) +) yt +JOIN ( + SELECT + yt_inner.custid, + MIN(yt_inner.year) AS first_year, + yt_inner.ord_total AS first_year_total + FROM ( + SELECT + o.custid, + EXTRACT(YEAR FROM o.orderdate) AS year, + SUM(ov."OrderTotal") AS ord_total + FROM "Sales"."Orders" o + JOIN public."OrderValues" ov ON o.orderid = ov.orderid + GROUP BY o.custid, EXTRACT(YEAR FROM o.orderdate) + ) yt_inner + JOIN ( + SELECT + custid, + MIN(EXTRACT(YEAR FROM orderdate)) AS first_year + FROM "Sales"."Orders" + GROUP BY custid + ) fy ON yt_inner.custid = fy.custid AND yt_inner.year = fy.first_year + GROUP BY yt_inner.custid, yt_inner.ord_total +) fyt ON yt.custid = fyt.custid +JOIN "Sales"."Customers" c ON yt.custid = c.custid +WHERE yt.year > fyt.first_year + AND yt.ord_total < fyt.first_year_total +ORDER BY yt.custid, yt.year; + +--7. Выведите следующую информацию о заказчиках и количестве сделанных ими заказов. Решите данную задачу 2 способами: +--a. Используя коррелированный подзапрос + +SELECT + c.companyname, + c.country, + ( + SELECT COUNT(*) + FROM "Sales"."Orders" o + WHERE o.custid = c.custid + ) AS org_qw +FROM "Sales"."Customers" c; + +--b. Используя подзапрос LATERAL + +SELECT + c.companyname, + c.country, + o_count.org_qw +FROM "Sales"."Customers" c +CROSS JOIN LATERAL ( + SELECT COUNT(*) AS org_qw + FROM "Sales"."Orders" o + WHERE o.custid = c.custid +) o_count; + +--8. Проанализируйте и объясните следующий запрос. + +-- with recursive hw(_array, i, r) as ( +-- Нерекурсивная часть: инициализация +-- Создаем массив символов, устанавливаем начальный индекс i=1 и пустую результирующую строку r='' +-- values (array['H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'], 1, '') +-- union all +-- Рекурсивная часть: обработка каждого следующего символа +-- Берем текущий массив, увеличиваем индекс i на 1, добавляем к строке r текущий символ из массива +-- select _array, i + 1, r || _array[i] from hw +-- Условие продолжения рекурсии: пока индекс i не превысил длину массива +-- where i <= array_length(_array, 1) +-- ) +-- Финальный SELECT: выводим все строки, сгенерированные рекурсивным CTE +-- select * from hw; + +-- Итого данный запрос генерирует последовательность строк, показывающую пошаговое построение фразы "Hello, world!" из отдельных символов массива, +-- начиная с пустой строки и заканчивая полной фразой.