Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 214 additions & 0 deletions hw4.sql
Original file line number Diff line number Diff line change
@@ -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!" из отдельных символов массива,
-- начиная с пустой строки и заканчивая полной фразой.