суббота, 30 марта 2024 г.

SQL Подзапросы и общие табличные выражения

 

SELECT *
FROM (SELECT m.rating,
             AVG(m.rental_rate) AS average_rental
        FROM movie AS m
      GROUP BY m.rating
      ORDER BY average_rental DESC
      LIMIT 5) AS best_rating;
Подзапросу во FROM нужно всегда назначать псевдоним, иначе произойдёт ошибка. Теперь можно провести вычисления по подзапросу во FROM:
SELECT AVG(best_rating.average_rental)
FROM (SELECT m.rating,
             AVG(m.rental_rate) AS average_rental
        FROM movie AS m
      GROUP BY m.rating
      ORDER BY average_rental DESC
      LIMIT 5) AS best_rating;


SELECT *
FROM client
WHERE customer_id IN (SELECT customer_id
                      FROM invoice
                      GROUP BY customer_id
                      ORDER BY SUM(total) DESC
                      LIMIT 10);
SELECT AVG(rental_rate)
FROM movie AS m
WHERE film_id IN (SELECT m.film_id
                  FROM movie AS m LEFT JOIN film_actor AS fa ON m.film_id = fa.film_id
                  GROUP BY m.film_id
                  HAVING COUNT(actor_id) > 12)
 AND length <= (SELECT AVG(length) 
                FROM movie AS m);
C таблицами, сформированными с помощью подзапросов, можно работать точно так же, как и с таблицами из базы данных. Часто таблицы объединяют уже после того, как получили срез и сгруппировали данные. Причина проста: объединение больших таблиц занимает много времени. Таблицу лучше предварительно обработать, а уже потом объединять данные. Использовать подзапросы — хорошее решение, но зачастую у них очень громоздкий вид. Что будет, если в одном запросе указать несколько подзапросов: пять, шесть и более? Решить проблему могут общие табличные выражения, или CTE (от англ. common table expressions).
WITH
-- назначение псевдонимов и формирование подзапросов
псевдоним_1 AS (подзапрос_1),
псевдоним_2 AS (подзапрос_2),
псевдоним_3 AS (подзапрос_3),
....
псевдоним_n AS (подзапрос_n)

SELECT -- основной запрос
-- внутри основного запроса работают с псевдонимами, которые назначили в WITH
FROM псевдоним_1 INNER JOIN псевдоним_2 ... 
...
...
К общим табличным выражениям нельзя обращаться после оператора WHERE
WITH 
-- первый подзапрос с псевдонимом i
i AS (SELECT billing_country AS country,
             COUNT(total) AS total_invoice
      FROM invoice
      GROUP BY billing_country
      ORDER BY total_invoice DESC
      LIMIT 5), -- подзапросы разделяют запятыми
-- второй подзапрос с псевдонимом c
 c AS (SELECT country AS country,
              COUNT(customer_id) AS total_clients
              FROM client
              GROUP BY country)

-- основной запрос, в котором указаны псевдонимы для подзапросов
SELECT i.country,
       i.total_invoice,
       c.total_clients
FROM i LEFT OUTER JOIN c ON i.country=c.country
ORDER BY i.total_invoice DESC;
WITH
top40 AS (SELECT *       
         FROM movie
         WHERE rental_rate>2
         ORDER BY length DESC
         LIMIT 40)

-- general query
SELECT top40.rating,
       MIN(length) AS min_length,
       MAX(length) AS max_length,
       AVG(length) AS avg_length,
       MIN(rental_rate) AS min_rental_rate,
       MAX(rental_rate) AS max_rental_rate,
       AVG(rental_rate) AS avg_rental_rate
FROM top40
GROUP BY top40.rating
ORDER BY avg_length ASC;
WITH
const_m AS (SELECT *
            FROM generate_series(1, 12) month),
t AS (SELECT 
            EXTRACT(YEAR FROM CAST(invoice_date AS timestamp)) AS year,
            EXTRACT(MONTH FROM CAST(invoice_date AS timestamp)) AS month,
            COUNT(*)
        FROM invoice
        GROUP BY year, month),
t11 AS (SELECT month, count as year_2011 FROM t WHERE year=2011),
t12 AS (SELECT month, count as year_2012 FROM t WHERE year=2012),
t13 AS (SELECT month, count as year_2013 FROM t WHERE year=2013)

SELECT const_m.month as invoice_month, 
       t11.year_2011, t12.year_2012, t13.year_2013
FROM const_m
LEFT JOIN t11 ON t11.month=const_m.month
LEFT JOIN t12 ON t12.month=const_m.month
LEFT JOIN t13 ON t13.month=const_m.month
ORDER BY invoice_month;

Комментариев нет:

Отправить комментарий