# GROUP BY
Results of a SELECT query can be grouped by one or more columns using the GROUP BY statement: all results with the same value in the grouped columns are aggregated together. This generates a table of partial results, instead of one result. GROUP BY can be used in conjunction with aggregation functions using the HAVING statement to define how non-grouped columns are aggregated.
# Basic GROUP BY example
It might be easier if you think of GROUP BY as "for each" for the sake of explanation. The query below:
"Give me the sum of MonthlySalary’s for each EmpID"
So if your table looked like this:
Sum wouldn’t appear to do anything because the sum of one number is that number. On the other hand if it looked like this:
Then it would because there are two EmpID 1’s to sum together.
# USE GROUP BY to COUNT the number of rows for each unique entry in a given column
Let’s say you want to generate counts or subtotals for a given value in a column.
Given this table, "Westerosians":
| Name | GreatHouseAllegience |
|---|---|
| Arya | Stark |
| Cercei | Lannister |
| Myrcella | Lannister |
| Yara | Greyjoy |
| Catelyn | Stark |
| Sansa | Stark |
Without GROUP BY, COUNT will simply return a total number of rows:
| Number_of_Westerosians |
|---|
| 6 |
But by adding GROUP BY, we can COUNT the users for each value in a given column, to return the number of people in a given Great House, say:
| House | Number_of_Westerosians |
|---|---|
| Stark | 3 |
| Greyjoy | 1 |
| Lannister | 2 |
It’s common to combine GROUP BY with ORDER BY to sort results by largest or smallest category:
| House | Number_of_Westerosians |
|---|---|
| Stark | 3 |
| Lannister | 2 |
| Greyjoy | 1 |
# Filter GROUP BY results using a HAVING clause
A HAVING clause filters the results of a GROUP BY expression. Note: The following examples are using the Library
Examples:
Return all authors that wrote more than one book (live example
Return all books that have more than three authors (live example
# ROLAP aggregation (Data Mining)
# Description
The SQL standard provides two additional aggregate operators. These use the polymorphic value "ALL" to denote the set of all values that an attribute can take. The two operators are:
- with data cube that it provides all possible combinations than the argument attributes of the clause.
- with roll up that it provides the aggregates obtained by considering the attributes in order from left to right compared how they are listed in the argument of the clause.
SQL standard versions that support these features: 1999,2003,2006,2008,2011.
# Examples
Consider this table:
| Food | Brand | Total_amount |
|---|---|---|
| Pasta | Brand1 | 100 |
| Pasta | Brand2 | 250 |
| Pizza | Brand2 | 300 |
# With cube
| Food | Brand | Total_amount |
|---|---|---|
| Pasta | Brand1 | 100 |
| Pasta | Brand2 | 250 |
| Pasta | ALL | 350 |
| Pizza | Brand2 | 300 |
| Pizza | ALL | 300 |
| ALL | Brand1 | 100 |
| ALL | Brand2 | 550 |
| ALL | ALL | 650 |
# With roll up
| Food | Brand | Total_amount |
|---|---|---|
| Pasta | Brand1 | 100 |
| Pasta | Brand2 | 250 |
| Pizza | Brand2 | 300 |
| Pasta | ALL | 350 |
| Pizza | ALL | 300 |
| ALL | ALL | 650 |
# Syntax
GROUP BY <
column-expression
| ROLLUP ( [ . n ] )
| CUBE ( [ . n ] )
| GROUPING SETS ( [ . n ] )
| () —calculates the grand total
> [ . n ]
Руководство по предложению GROUP BY в SQL
Перевод статьи « SQL Group By Tutorial: Count, Sum, Average, and Having Clauses Explained».

Предложение GROUP BY это очень мощный параметр, но и непростой. Даже спустя восемь лет его использования я все еще каждый раз задумываюсь, что, собственно, я делаю.
В этой статье мы рассмотрим, как составляется предложение GROUP BY , какова роль этого параметра в вашем запросе и как его можно использовать для осуществления агрегаций и сбора информации о ваших данных.
Мы рассмотрим следующие темы:
Подготовительный этап с описанием программного обеспечения и созданием базы данных мы рассматривали в двух предыдущих статьях:
-
. (Раздел «Настройка базы данных») . (Раздел «Настройка базы данных»)
Эти разделы совершенно идентичны, так что можете почитать в любой из двух статей.
Создание таблицы с данными
Для нашего примера мы создадим таблицу, в которой будут храниться записи о продажах различных продуктов в разных точках.
Таблицу мы назовем sales . Это будет простое представление продаж в магазинах: название локации, название продукта, цена и время продажи.
Если бы мы создавали такую таблицу для настоящего приложения, мы бы использовали внешние ключи к другим таблицам (например, locations или products ). Но чтобы показать работу GROUP BY , мы создадим простые TEXT -столбцы.
Давайте создадим нашу таблицу и внесем в нее кое-какие данные о продажах:
У нас есть три локации: HQ , Downtown , и 1st Street .
Также у нас есть два продукта: Coffee и Bagel (кофе и бублики). Продажи мы вносим с разными значениями sold_at , чтобы показать, сколько товаров было продано в разные дни и разное время.
У нас были продажи сегодня, вчера и позавчера.
Как работает GROUP BY?
Чтобы показать, как работает GROUP BY , давайте рассмотрим пример.
Представьте, что у нас есть комната, в которой находится много людей. Эти люди родились в разных странах.
Если мы хотим найти средний рост людей, находящихся в этой комнате, в разрезе по странам, мы сначала попросим их разделиться на группы по стране рождения.
Когда люди сгруппируются по месту рождения, мы сможем высчитать средний рост в каждой группе.
Вот так и работает предложение GROUP BY . Сначала мы определяем, как мы хотим сгруппировать строки, а затем осуществляем вычисления или агрегации в группах.
Множественные группы
Мы можем группировать данные в любое количество групп и подгрупп.
Например, когда люди разделились по странам, мы можем попросить их в каждой группе разделиться на подгруппы по цвету глаз.
Таким образом мы получим группы людей, родившихся в одной стране и имеющих одинаковый цвет глаз.
После этого мы можем высчитать средний рост в каждой такой маленькой группе и получить более специфический результат. Например, средний рост голубоглазых людей, родившихся во Франции.
Предложения GROUP BY часто используются в случаях, когда можно использовать обороты по чему-то или в каждом(ой):
- средний рост по стране рождения,
- общее число людей в каждой комбинации цвета глаз и волос,
- общее число продаж по каждому продукту.
Написание предложений GROUP BY
Предложение GROUP BY пишется очень просто. Мы используем ключевые слова GROUP BY и указываем поля, по которым должна происходить группировка:
Этот простой запрос группирует данные таблицы sales по столбцу location .
Ну хорошо, мы их сгруппировали, но что нам поместить в наш SELECT ?
Очевидно, что нам нужно сделать выборку локации. Мы группируем данные по этому столбцу и как минимум хотим увидеть имена созданных групп:
Результатом будут три наши локации:
Если мы посмотрим на необработанные данные нашей таблицы ( SELECT * FROM sales; ), мы увидим, что у нас есть четыре строки с локацией HQ , две строки с локацией Downtown и еще две — с локацией 1st Street :
Группируя данные по столбцу location , наша база данных берет эти входные строки и определяет среди них уникальные локации. Эти уникальные локации служат в качестве «групп».
А как насчет остальных столбцов таблицы?
Если мы попробуем выбрать столбец product , по которому мы не делали группировку,
мы получим вот такую ошибку:
Проблема в том, что мы взяли восемь строк и попытались втиснуть их в три.
Мы не можем просто возвращать оставшиеся столбцы, как обычно, потому что раньше у нас было восемь строк, а теперь их только три.
Что делать с оставшимися пятью строками данных? Какие данные из восьми строк должны быть отображены в трех строках?
На эти вопросы нет четкого и ясного ответа.
Чтобы использовать остальные данные таблицы, мы должны выделить данные из оставшихся столбцов в наши три локационные группы.
Это означает, что мы должны агрегировать эти данные или осуществить какие-то вычисления, чтобы получить некую итоговую информацию об оставшихся данных.
Агрегатные функции (COUNT, SUM, AVG)
Если мы решили сгруппировать данные, мы можем агрегировать данные оставшихся столбцов. например, мы можем посчитать число строк в каждой группе, суммировать отдельные значения в группе или вывести некое среднее значение (тоже по группе).
Для начала давайте найдем количество продаж по каждой локации.
Поскольку каждая запись в таблице sales это запись об одной продаже, число продаж по локации будет равно числу строк в каждой группе (при группировке по локациям).
Чтобы получить нужный результат, нам нужно применить агрегатную функцию COUNT() — так мы вычислим количество строк в каждой группе.
Мы используем COUNT(*) , чтобы считать все входящие строки в группе.
( COUNT() также работает с выражениями, но при этом имеет несколько другое поведение).
Вот как база данный выполняет наш запрос:
- FROM sales — Сначала получи все записи из таблицы sales.
- GROUP BY location — Затем определи уникальные группы при группировке по локации (т. е. уникальные локации).
- SELECT … — Наконец, выбери имя локации и посчитай число строк в этой группе.
Чтобы сделать вывод более читабельным, мы даем числу строк псевдоним — при помощи AS number_of_sales . Выглядит это так:
Локация 1st Street имеет две продажи, HQ — четыре, а Downtown — две.
Как видно, здесь мы взяли данные столбца, по которому не делали группировку, и из восьми отдельных строк вычленили полезную итоговую информацию по каждой локации, а именно — число продаж.
Вместо подсчета числа строк в группе мы могли бы суммировать информацию по группе. Например, получить общее количество вырученных денег по каждой локации.
Для этого мы будем использовать функцию SUM() :
Вместо подсчета числа строк в каждой группе мы сложили количество долларов, полученных в результате каждой продажи, и вывели общий доход по локациям:
Функция AVG() позволяет находить среднее значение (AVG от Average — среднее). Давайте найдем среднюю сумму выручки по локациям. Для этого просто заменим функцию SUM() на функцию AVG() :
Работа с несколькими группами
Пока что мы работали с одной группировкой — по локациям. Что, если нам нужно разбить полученные группы на подгруппы?
Вспомните пример сценария, приведенный в начале статьи, с группировкой людей по цвету глаз и стране происхождения. Давайте попробуем найти число продаж каждого продукта в каждой отдельной локации (Например, сколько было продаж кофе, а сколько — бубликов на 1st Street , HQ и Downtown ).
Для этого нам нужно добавить к нашему предложению GROUP BY второе группирующее условие:
Добавив название еще одного столбца в наше предложение GROUP BY , мы разделили наши локационные группы на подгруппы по продуктам.
Поскольку теперь мы группируем также по столбцу product, мы можем вернуть результат при помощи нашего SELECT !
(Для облегчения чтения я добавил в запрос также предложения ORDER BY ).
В результатах нашего нового группирования мы видим уникальные комбинации локаций и продуктов:
Ну хорошо, у нас есть наши группы, а что мы будем делать с данными остальных столбцов?
Мы можем найти число продаж определенного продукта в каждой локации, используя все те же агрегатные функции:
(Задание «со звездочкой»: найдите общую выручку (сумму) за каждый продукт в каждой локации).

Использование функций в GROUP BY
Давайте попытаемся найти общее число продаж в день.
Следуя тому же шаблону, который применяли со столбцом sold_at ,
мы можем ожидать, что каждая группа будет уникальным днем, но вместо этого видим следующее:
Похоже, наши данные вообще не сгруппировались: мы получили каждую строку отдельно.
Но на самом деле наши данные сгруппированы! Проблема в том, что sold_at каждой строки является уникальным значением, поэтому каждая строка образует собственную группу!
GROUP BY работает правильно, однако это не тот результат, который нам нужен.
Виной всему уникальная информация временной метки (часы/минуты/секунды).
Все эти временные метки разные, поэтому записи разбрасываются по разным группам.
Нам нужно конвертировать значения даты и времени для каждой записи в просто дату:
После этого все записи о продажах, сделанных в один день, будут иметь одинаковое значение даты и, следовательно, попадут в одну группу.
Для этого мы сведем значение временной метки sold_at к дате:
В нашем предложении GROUP BY мы используем ::DATE , чтобы обрезать временную метку до «дня». Таким образом мы эффективно отрезаем часы/минуты/секунды и возвращаем просто день.
В запросе SELECT мы возвращаем то же выражение и даем ему псевдоним для более красивого вывода.
По той же причине, по которой нельзя вернуть product , не сгруппировав данные по этому столбцу или не совершив каких-то вычислений, база данных не позволит нам и вернуть просто sold_at . В SELECT все должно быть или в GROUP BY , или как-то агрегировано по группам.
Вот результат числа продаж за день, который мы хотели увидеть:
Фильтрация групп при помощи HAVING
Давайте теперь разберем, как можно фильтровать наши сгруппированные строки. Например, попробуем найти дни, в которые у нас было больше одной продажи.
Не применяя группирование, мы могли бы отфильтровать наши строки, используя предложение WHERE . Например:
Имея группы, мы можем попробовать отфильтровать наши группы по числу строк…
К сожалению, это не сработало и мы получили ошибку:
В предложениях WHERE агрегатные функции недопустимы, потому что WHERE вычисляется до предложения GROUP BY , то есть в момент, когда еще никаких групп нет.
Но есть одно предложение, позволяющее нам фильтровать записи и осуществлять агрегации, и оно срабатывает после предложения GROUP BY . Это предложение HAVING .
Предложение HAVING это как предложение WHERE , только для групп.
Чтобы найти дни, в которые было больше одной продажи. мы можем добавить предложение HAVING , которое проверит число строк в группе:
Это предложение HAVING отфильтровывает все строки, если число строк в группе не больше одной. Вот результат:
Чисто для полноты картины вот вам порядок выполнения всех предложений SQL:
- FROM — получает все записи из указанной таблицы
- JOIN — осуществляет соединения
- WHERE — фильтрует строки
- GROUP BY — формирует группы
- HAVING — фильтрует группы
- SELECT — выбирает данные для возврата
- ORDER BY — упорядочивает строки вывода
- LIMIT — возвращает определенное число строк.
Агрегации со скрытым группированием
Последняя тема, которую мы затронем, это агрегации без GROUP BY или, если выражаться более точно, агрегации со скрытым группированием.
Эти агрегации полезны в сценариях, где вы хотите найти одну конкретную агрегацию из таблицы. Например, общую выручку или наибольшее/наименьшее значение столбца.
Мы могли бы найти общую выручку по всем локациям, просто выбрав сумму по всей таблице:
На данный момент в результате всех продаж по всем локациям мы получили $19 (ура!).
Еще один полезный сценарий — запросить первое или последнее что-нибудь.
Например, дату самой первой продажи.
Чтобы ее найти, мы моем применить функцию MIN() :
(Для поиска даты последней продажи нужно всего лишь заменить MIN() на MAX() ).
Использование MIN / MAX
Хотя эти простые запросы могут быть полезны сами по себе, они часто являются составляющими более длинных запросов.
Например, давайте попробуем найти общую выручку в последний день, когда у нас вообще были продажи.
Мы можем написать запрос так:
Этот запрос сработает, но мы захардкодили дату 2020-09-01. А ведь дата последней продажи будет постоянно меняться. Нам нужно динамическое решение.
Для этого нам нужно скомбинировать этот запрос с функцией MAX() в подзапросе:
В нашем предложении WHERE , используя подзапрос, мы нашли самую последнюю дату в таблице: SELECT MAX(sold_at::DATE) FROM sales .
Затем мы использовали эту «максимальную» дату в качестве значения, по которому фильтруется таблица, и суммировали выручку по каждой продаже.
Скрытое группирование
Я назвал это скрытым группированием, потому что если мы попытаемся вот так выбрать агрегированное значение с не-агрегированным столбцом —
мы получим уже знакомую ошибку:
GROUP BY — это инструмент
Как и многие другие вещи в сфере разработки, GROUP BY — это инструмент.
Есть много способов писать и переписывать эти запросы, используя комбинации GROUP BY , агрегатных функций и других инструментов, таких как DISTINCT , ORDER BY и LIMIT .
Чтобы понять, как работает GROUP BY , нужно немного попрактиковаться. Но когда вы разберетесь, то поймете, что теперь можете куда легче решать многие задачи!
Grokking GROUP BY
Understanding the SQL GROUP BY Clause and Aggregate Functions
Please note: the examples in this article were created with PostgreSQL, and other varieties of SQL may produce slightly different results.
Introduction
Upon first encountering the SQL GROUP BY clause, it appears simple enough. It’s easy to understand that GROUP BY forms groups of rows based on columns which share a common value. It’s also easy to understand that those groups can be used to refine our queries and produce more meaningful results based on those groups. However, when we begin using GROUP BY, we may find that it is also very easy to produce errors. There are certain requirements when using GROUP BY and if these are not sufficiently understood (or grokked) errors become likely occurrences. In this article, I will attempt to demonstrate what these requirements are, why they are necessary, and how GROUP BY can be used with ease to attain powerful results. Let’s begin!
What does GROUP BY do?
Most simply put, the GROUP BY clause makes groups of rows where values in the specified columns are the same. Those groups are then used in the final output of the query.
In the results, a row can contain values from grouped columns and ungrouped columns which belong to the same group. It is important to note that the output can only contain one value for each column in the group. The value for a grouped column will be the shared value of each row in the group. The value for an ungrouped column will be the single value that is the result of aggregating all of the values in the column within the group.
If this is already starting to get confusing, then let’s see how it works in action.
For the rest of this article, we will be working with the following data set about a number of pets which have various traits and belong to various categories. Right now, the data is quite messy, but we will see how GROUP BY can be used to make sense of our data in many ways.
Let’s start with a very simple example and return a list of all the species:
We know that our data set has 10 rows, and the results of our query returned 7 rows. That’s because the query produced 7 groups in which the value in the species column is the same. We can see this more clearly with the following visualization of the grouped data.
Notice how the values in the grouped column are condensed to a single value in the output, e.g. ‘dog’ occurs twice in the species column, but only once in the output.
Let’s also take a look at what happens if we group the data set by class:
So far so good. Let’s try to return the names of all of the pets grouped by class:
This is where we start to run into trouble. Our error message reveals that the name column needs to be included in the GROUP BY clause, or be used in an aggregate function. The reason for this is that each column in the output must only contain one value per group. Since there are multiple names, we get an error. To understand this better, lets compare the situation with a real world example.
A Simple Analogy
Let’s say that a teacher divides their class into groups of students based on their eye colors.
The teacher then says, ‘Ok, brown-eyed kids, how old are you?’
The kids freeze. Some kids are 8, and some are 9. They don’t know how to respond. It’s impossible for them to choose a single age for all of the kids in the group.
However, one brave and clever student does respond, ‘Teacher, we need more information. Do you mean the average of our ages, or all of our ages in a list?’
You can probably see where I’m going with this. SQL runs into the same problem that the students did. If the data is not grouped, or aggregated, an error will be thrown, just like the brave and clever student asking for better instructions.When there are multiple values in a group, SQL can not choose a single value to represent, and needs to be told in exactly what way the values should be combined together to produce one value. This is precisely what aggregate functions do.
Aggregate Functions
An aggregate function is simply a function which takes multiple values, performs some operation on them, and then produces a single value as a result. This is exactly what is needed if we want to include some information from an ungrouped column in the output of a data set that has been grouped with GROUP BY. That way, wherever there is a group of rows, and some rows have multiple different values in a column, those different values can be combined in some way to form a single value for that group.
There are many different aggregate functions, which can be explored here, but a few very useful aggregate functions include:
- count(column_name) — This will return the number of rows in the group.
- sum(column_name) — This will add up the numeric values of all the rows in the specified column in the group.
- string_agg(column_name, delimiter) — This will concatenate all of the string values separated by the delimiter of all of the rows in the specified column in the group.
With this understanding of aggregate functions, let’s try again to return all of the names of the pets grouped by class. Since we know we must combine them as a single value, let’s use the string_agg function to do just that.
This time we are successful. The values in the name column have been aggregated into a single value (as shown by the highlighted blocks above) and can now be included in the results. The diagram above also shows how the grouped column class is also essentially aggregated from many identical values to a single value.
Let’s entrench our understanding with another quick example. This time, we want to discover the total weight of each class of animals. This time, we’ll use the sum function.
The HAVING Clause
Let’s dive a little deeper and say that we want to find out all of the species of animals of which there are more than one pet. For this we’re going to need to filter out all of the species groups which have one or less pets. The WHERE clause won’t work because we need a way to count the animals in each group and aggregate functions are not valid in a WHERE clause. Luckily, there is another clause which is meant for just this purpose, the HAVING clause. The HAVING clause filters groups by comparing them to a conditional statement. If the comparison returns true, the group is included in the results, otherwise the group is not included. Let’s try it out.
In the diagram above, we can see that rows are first grouped by species, then filtered by the HAVING clause. the HAVING clause selects only groups which have a count of more than 1 row. All others are eliminated from the results.
Functional Dependency
Before this article comes to a close, there is one more subject to explore, the concept of functional dependency. The PostgreSQL documentation has this to say:
When GROUP BY is present, or any aggregate functions are present, it is not valid for the SELECT list expressions to refer to ungrouped columns except within aggregate functions or when the ungrouped column is functionally dependent on the grouped columns, since there would otherwise be more than one possible value to return for an ungrouped column. A functional dependency exists if the grouped columns (or a subset thereof) are the primary key of the table containing the ungrouped column.
We have already explored the first condition in the above statement, namely that ungrouped columns cannot be included in the SELECT list except within aggregate functions. We have not yet looked at the second valid condition for an ungrouped column, that it may exist in the SELECT list if it is functionally dependent on one of the grouped columns. The above statement declares that ‘a functional dependency exists if one of the grouped columns is the primary key of the table containing the ungrouped column.’ That is likely not too hard to understand, but let’s make it even more clear with a quick example. Let’s select the names of the pets grouped by their id (the primary key of the table).
That worked well. One thing that is important to note here is that the name column was included in the SELECT list without using an aggregate function or including it in the GROUP BY clause. This is possible because the name column (and all of the other columns in the table) is functionally dependent on the id column which was explicitly set as a primary key. Every primary key requires that it’s values be unique and not null, which means that if the table is grouped by these values, each group will be comprised of only one row as there cannot by definition be multiple rows in the table with the same value. If multiple tables are joined together, there can be multiple rows with the same primary key value, but all of the values in the original table will belong to only one primary key, which is another way to say that those values are functionally dependent on the primary key.
Let’s look at one final example before closing. This time we will try to select the id values of the pets table grouped by name. All of the names are different, so there should be only one id value per name. Will this work? Let’s try it out.
This doesn’t work. Even though we satisfy the condition that there can only be one value per group, the id column is not functionally dependent on the name column. The technical reason for this is that the name column is not the primary key of the table. Another reason is that the name column could have multiple values which are the same and then form groups of multiple rows. However, even if UNIQUE and NOT NULL constraints were set on the name column, it would not be the primary key and would not technically satisfy the definition of functional dependency.
Conclusion
In this article, I have tried to clarify some of the confusion that can arise when using the GROUP BY clause. The main thing to remember is that GROUP BY forms groups and each group can only contain a single value per column in the results. Grouped columns are automatically condensed into a single value, while ungrouped columns must either be aggregated into a single value or be functionally dependent on one of the grouped columns.
I hope this article enhanced your understanding of the GROUP BY statement and will help you to avoid some of those frustrating errors.
SQL запросы быстро. Часть 1
Язык SQL очень прочно влился в жизнь бизнес-аналитиков и требования к кандидатам благодаря простоте, удобству и распространенности. Из собственного опыта могу сказать, что наиболее часто SQL используется для формирования выгрузок, витрин (с последующим построением отчетов на основе этих витрин) и администрирования баз данных. И поскольку повседневная работа аналитика неизбежно связана с выгрузками данных и витринами, навык написания SQL запросов может стать фактором, из-за которого кандидат или получит преимущество, или будет отсеян. Печальная новость в том, что не каждый может рассчитывать получить его на студенческой скамье. Хорошая новость в том, что в изучении SQL нет ничего сложного, это быстро, а синтаксис запросов прост и понятен. Особенно это касается тех, кому уже доводилось сталкиваться с более сложными языками.
Обучение SQL запросам я разделил на три части. Эта часть посвящена базовому синтаксису, который используется в 80-90% случаев. Следующие две части будут посвящены подзапросам, Join’ам и специальным операторам. Цель гайдов: быстро и на практике отработать синтаксис SQL, чтобы добавить его к арсеналу навыков.
Практика
Введение в синтаксис будет рассмотрено на примере открытой базы данных, предназначенной специально для практики SQL. Чтобы твое обучение прошло максимально эффективно, открой ссылку ниже в новой вкладке и сразу запускай приведенные примеры, это позволит тебе лучше закрепить материал и самостоятельно поработать с синтаксисом.
Кликнуть здесь
После перехода по ссылке можно будет увидеть сам редактор запросов и вывод данных в центральной части экрана, список таблиц базы данных находится в правой части.
Структура sql-запросов
Общая структура запроса выглядит следующим образом:
Разберем структуру. Для удобства текущий изучаемый элемент в запроса выделяется CAPS’ом.
SELECT, FROM
SELECT, FROM — обязательные элементы запроса, которые определяют выбранные столбцы, их порядок и источник данных.
Выбрать все (обозначается как *) из таблицы Customers:
Выбрать столбцы CustomerID, CustomerName из таблицы Customers:
WHERE
WHERE — необязательный элемент запроса, который используется, когда нужно отфильтровать данные по нужному условию. Очень часто внутри элемента where используются IN / NOT IN для фильтрации столбца по нескольким значениям, AND / OR для фильтрации таблицы по нескольким столбцам.
Фильтрация по одному условию и одному значению:
Фильтрация по одному условию и нескольким значениям с применением IN (включение) или NOT IN (исключение):
Фильтрация по нескольким условиям с применением AND (выполняются все условия) или OR (выполняется хотя бы одно условие) и нескольким значениям:
GROUP BY
GROUP BY — необязательный элемент запроса, с помощью которого можно задать агрегацию по нужному столбцу (например, если нужно узнать какое количество клиентов живет в каждом из городов).
При использовании GROUP BY обязательно:
- перечень столбцов, по которым делается разрез, был одинаковым внутри SELECT и внутри GROUP BY,
- агрегатные функции (SUM, AVG, COUNT, MAX, MIN) должны быть также указаны внутри SELECT с указанием столбца, к которому такая функция применяется.
Группировка количества клиентов по стране и городу:
Группировка продаж по ID товара с разными агрегатными функциями: количество заказов с данным товаром и количество проданных штук товара:
Группировка продаж с фильтрацией исходной таблицы. В данном случае на выходе будет таблица с количеством клиентов по городам Германии:
Переименование столбца с агрегацией с помощью оператора AS. По умолчанию название столбца с агрегацией равно примененной агрегатной функции, что далее может быть не очень удобно для восприятия.
HAVING
HAVING — необязательный элемент запроса, который отвечает за фильтрацию на уровне сгруппированных данных (по сути, WHERE, но только на уровень выше).
Фильтрация агрегированной таблицы с количеством клиентов по городам, в данном случае оставляем в выгрузке только те города, в которых не менее 5 клиентов:
В случае с переименованным столбцом внутри HAVING можно указать как и саму агрегирующую конструкцию count(CustomerID), так и новое название столбца number_of_clients:
Пример запроса, содержащего WHERE и HAVING. В данном запросе сначала фильтруется исходная таблица по пользователям, рассчитывается количество клиентов по городам и остаются только те города, где количество клиентов не менее 5:
ORDER BY
ORDER BY — необязательный элемент запроса, который отвечает за сортировку таблицы.
Простой пример сортировки по одному столбцу. В данном запросе осуществляется сортировка по городу, который указал клиент:
Осуществлять сортировку можно и по нескольким столбцам, в этом случае сортировка происходит по порядку указанных столбцов:
По умолчанию сортировка происходит по возрастанию для чисел и в алфавитном порядке для текстовых значений. Если нужна обратная сортировка, то в конструкции ORDER BY после названия столбца надо добавить DESC:
Обратная сортировка по одному столбцу и сортировка по умолчанию по второму:
JOIN — необязательный элемент, используется для объединения таблиц по ключу, который присутствует в обеих таблицах. Перед ключом ставится оператор ON.
Запрос, в котором соединяем таблицы Order и Customer по ключу CustomerID, при этом перед названиям столбца ключа добавляется название таблицы через точку:
Нередко может возникать ситуация, когда надо промэппить одну таблицу значениями из другой. В зависимости от задачи, могут использоваться разные типы присоединений. INNER JOIN — пересечение, RIGHT/LEFT JOIN для мэппинга одной таблицы знаениями из другой,
Внутри всего запроса JOIN встраивается после элемента from до элемента where, пример запроса:
Другие типы JOIN’ов можно увидеть на замечательной картинке ниже:
В следующей части подробнее поговорим о типах JOIN’ов и вложенных запросах.