6 простых способов использовать передовые методы SQL

6 простых способов использовать передовые методы SQL

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

1. Оконные функции для сложных вычислений

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

Текущий итог

SELECT category, SUM(revenue) OVER (PARTITION BY category ORDER BY date) AS running_total FROM sales_data;

В этом примере функция SUM используется для расчёта общей выручки по каждой товарной категории. Предложение OVER используется для определения окна, в пределах которого будет вычисляться функция. Предложение PARTITION BY используется для группировки данных по категориям продуктов, а предложение ORDER BY используется для сортировки данных по дате. Результатом является таблица, в которой показан текущий общий доход по каждой товарной категории.

Скользящая средняя

SELECT date, AVG(amount) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS moving_avg FROM sales ORDER BY date;

Здесь функция AVG используется с предложением OVER для вычисления скользящего среднего. Предложение ORDER BY указывает, что данные должны быть упорядочены по дате, а предложение ROWS BETWEEN 6 PREVIOUS AND CURRENT ROW указывает, что среднее значение должно быть рассчитано для текущей строки и шести предыдущих строк.

Верхние n строк

SELECT date, region, amount, DENSE_RANK() OVER (PARTITION BY region ORDER BY amount DESC) AS rank FROM sales WHERE rank <= 3;

Здесь функция DENSE_RANK используется с предложением OVER для присвоения ранга каждой строке на основе объёма продаж в порядке убывания. В предложении PARTITION BY указано, что расчёт должен выполняться отдельно для каждого региона, а в предложении ORDER BY указано, что расчёт должен выполняться в порядке увеличения объема продаж.

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

Процентили

SELECT student_id, score, PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY score) OVER (PARTITION BY student_id) AS percentile_90 FROM scores;

Здесь функция PERCENTILE_CONT используется с предложением OVER для вычисления 90-го процентильного балла для каждого учащегося. PARTITION BY указывает, что расчёт должен выполняться отдельно для каждого учащегося, а пункт ORDER BY указывает, что расчёт должен выполняться в порядке получения баллов. Предложение WITHIN GROUP указывает, что вычисление процентиля должно выполняться внутри группы баллов для каждого учащегося.

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

2. Оконные функции для сравнения строк

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

Получить предыдущее или следующее значение

SELECT order_date, order_total, LAG(order_total) OVER (ORDER BY order_date) AS previous_order_total, order_total - LAG(order_total) OVER (ORDER BY order_date) AS order_total_diff FROM orders;

Этот запрос вычисляет разницу между общим объемом текущего заказа и общим объёмом предыдущего заказа для каждого заказа, используя функцию LAG и предложение ORDER BY.

Получить первое или последнее значение

SELECT customer_id, order_date, order_total, FIRST_VALUE(order_total) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS last_order_total LAST_VALUE(order_total) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS last_order_total FROM orders;

Этот запрос получает общую сумму первого и последнего заказов для каждого клиента, используя функции FIRST_VALUE и LAST_VALUE соответственно, с предложениями PARTITION BY и ORDER BY для определения окна.

Сегменты гистограмм

SELECT product_id, price, WIDTH_BUCKET(price, 0, 100, 4) AS bucket_number FROM products;

Этот запрос группирует товары в четыре блока гистограммы на основе их цены, используя функцию WIDTH_BUCKET и минимальное значение, максимальное значение и количество блоков, указанных в аргументах функции. Результирующий набор включает идентификатор продукта, цену и присвоенный номер корзины.

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

3. Общие табличные выражения и подзапросы

Непрекращающиеся дебаты в сообществе SQL по поводу распространённых табличных выражений и подзапросов так же горячо оспариваются, как и извечный спор о том, является ли "Крепкий орешек" рождественским фильмом или нет. Независимо от того, предпочитаете ли вы элегантность CTE или универсальность подзапросов, выбор в конечном счёте сводится к тому, что лучше всего подходит для ваших конкретных потребностей в данных."Крепкий орешек" - это рождественский фильм? Скорее всего, нет. Я всё ещё смотрю его каждый праздничный сезон? Да, смотрю! Вам не нужно выбирать между CTE и подзапросами, просто когда их использовать, чтобы ваши запросы выполнялись как у Джона Макклейна, эффективно и неостановимо (или, по крайней мере, не застревали в вентиляционной шахте).

CTEs

WITH revenue_by_category AS ( SELECT category, SUM(revenue) AS total_revenue FROM sales_data GROUP BY category ) SELECT category, total_revenue, total_revenue / (SELECT SUM(total_revenue) FROM revenue_by_category) AS revenue_share FROM revenue_by_category

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

Подзапросы

SELECT * FROM customers WHERE customer_id IN ( SELECT customer_id FROM orders GROUP BY customer_id ORDER BY COUNT(*) DESC LIMIT 10 )

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

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

4. Рекурсивные общие табличные выражения (CTEs)

Петли? В SQL? Еще бы! С помощью рекурсивных общих табличных выражений (CTEs) вы можете создавать циклы, которые позволяют исследовать иерархические структуры данных, такие как деревья и графики, мощным и гибким способом. Вызывая запрос внутри самого себя, вы можете разбить сложные задачи анализа данных на более мелкие, более управляемые части и повторять их до тех пор, пока не получите нужную информацию.

Вот пример рекурсивного CTE, который вычисляет общую стоимость продукта и всех его компонентов:

WITH RECURSIVE product_cost AS ( SELECT id, cost, id AS component_id FROM products WHERE id = 1 UNION ALL SELECT products.id, products.cost, product_cost.component_id FROM products JOIN product_components ON products.id = product_components.product_id JOIN product_cost ON product_components.component_id = product_cost.id ) SELECT component_id, SUM(cost) AS total_cost FROM product_cost GROUP BY component_id

В этом примере рекурсивный CTE с именем product_cost используется для вычисления общей стоимости продукта и всех его компонентов. Базовый вариант определяется в первой части CTE, где выбирается стоимость исходного продукта. Рекурсивный случай определён во второй части CTE, где выбирается стоимость компонентов продукта и объединяется с предыдущими результатами. Рекурсия продолжается до тех пор, пока не будут обработаны все компоненты. Наконец, основной запрос вычисляет общую стоимость каждого компонента путем группировки по столбцу component_id.

5. Самостоятельные соединения

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

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

SELECT e.name AS employee_name, m.name AS manager_name FROM employees e JOIN employees m ON e.manager_id = m.employee_id;

В этом примере мы присоединяем таблицу “employees” к самой себе, используя столбец “manager_id” и присоединяясь к столбцу “employee_id”. Результатом этого запроса будет таблица с двумя столбцами: “employee_name” и “manager_name”.

6. PIVOT

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

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

Вот пример того, как вы можете сводить данные с помощью PIVOT:

SELECT * FROM ( SELECT category, year, revenue FROM sales ) sales PIVOT ( SUM(revenue) FOR year IN ([2018], [2019], [2020]) ) AS sales_pivot;

И вот как вы можете достичь этих результатов, используя операторы CASE:

SELECT category, SUM(CASE WHEN year = '2018' THEN revenue ELSE 0 END) AS `2018`, SUM(CASE WHEN year = '2019' THEN revenue ELSE 0 END) AS `2019`, SUM(CASE WHEN year = '2020' THEN revenue ELSE 0 END) AS `2020` FROM sales GROUP BY category;

В обоих примерах SQL-запрос выбирает данные из таблицы “sales” и группирует их по столбцу “category”. Затем мы используем функции SUM с операторами PIVOT или CASE для создания трёх новых столбцов, содержащих выручку по каждой категории за каждый из 2018, 2019 и 2020 годов.

Надеюсь, что данная статья оказалась полезной для вас!

Статья была взята из этого источника:

9999 показов
752752 открытия
Начать дискуссию