SQL GROUP BY Clause

In this lesson, you will learn how to group rows that have common values using SQL.

The GROUP BY Clause In SQL

The GROUP BY clause can be used in conjunction with the aggregate functions to group the returned rows that have common values and then perform calculations based on those groups.

For example, to discover how many users you have in each country you can group the result based on the country column, then with the COUNT() function you can display the number of users in each country.


Syntax

SELECT column_name(s)
FROM table_name
WHERE condition
GROUP BY column_name(s)
ORDER BY column_name(s); 

The WHERE clause is applied before grouping the result, but the ORDER BY operator is applied after grouping the result. That's why the GROUP BY clause is put in the middle.

Preparing A Database

Since you will learn how to group the retrieved rows, you must have a database table with some records having common data to practice grouping them. Execute the following query to create the database.

Example

-- If there is already a database named "demo" delete it
DROP DATABASE IF EXISTS demo;

-- Create a new database called "demo"
CREATE DATABASE demo;

-- Select the "demo" database
USE demo;

-- Create a new table called "employees" inside the selected database
CREATE TABLE employees (
    id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50),
    gender VARCHAR(20),
    country VARCHAR(100),
    salary DECIMAL(7,2)
);

-- Insert 10 records in the "employees" table
-- We add null in the id column because its value will be generated automatically by the database server
INSERT INTO employees VALUES (null, "Emily", "female", "Denmark", 800);
INSERT INTO employees VALUES (null, "Stacy", "female", "Australia", 900);
INSERT INTO employees VALUES (null, "John", "male", "Canada", 750);
INSERT INTO employees VALUES (null, "Lana", "female", "Germany", 1000);
INSERT INTO employees VALUES (null, "Ronaldo", "male", "Brazil", 845);
INSERT INTO employees VALUES (null, "Louise", "female", "France", 700);
INSERT INTO employees VALUES (null, "James", "male", "Canada", 920);
INSERT INTO employees VALUES (null, "Maria", "female", "Brazil", 850);
INSERT INTO employees VALUES (null, "Mia", "female", "Canada", 780);
INSERT INTO employees VALUES (null, "Luke", "male", "Japan", 880);
    

This is the employees table that we created in the demo database.

id username gender country salary
1 Emily female Denmark 800.00
2 Stacy female Australia 900.00
3 John male Canada 750.00
4 Lana female Germany 1000.00
5 Ronaldo male Brazil 845.00
6 Louise female France 700.00
7 James male Canada 920.00
8 Maria female Brazil 850.00
9 Mia female Canada 780.00
10 Luke male Japan 880.00

Group By Single Column

The following query groups all employees based on their country and returns the country. So It will returns unique values.

Note: It's better to use the DISTINCT keyword if your purpose is just to return unique values.

Example 1

SELECT country
FROM employees
GROUP BY country;
    

Same query can be written as follows.

SELECT DISTINCT country
FROM employees;
    

Output

country
Denmark
Australia
Canada
Germany
Brazil
France
Japan

The following query returns the number of employees in each country.
We group the rows that have the same country, and then we count the number of rows in each group.

Example 2

SELECT country AS 'Country', COUNT(*) AS 'Total Employees'
FROM employees
GROUP BY country;
    

Output

Country Total Employees
Denmark 1
Australia 1
Canada 3
Germany 1
Brazil 2
France 1
Japan 1

The following query returns the number of employees in each country in descending order.
We group the rows that have the same country, and then we count the number of rows in each group, and then we sort the result in descending order.

Example 3

SELECT country AS 'Country', COUNT(*) AS 'Total_Employees'
FROM employees
GROUP BY country
ORDER BY Total_Employees DESC;
    

Output

Country Total_Employees
Canada 3
Brazil 2
Denmark 1
Australia 1
Germany 1
France 1
Japan 1

The following query returns the number of male employees in each country in descending order.
We group the rows that have the same country, and then we keep the rows where the gender is male, and then we count the number of rows in each group, and then we sort the result in descending order.

Example 4

SELECT country AS 'Country', COUNT(*) AS 'Total_Male_Employees'
FROM employees
WHERE gender = 'male'
GROUP BY country
ORDER BY Total_Male_Employees DESC;
    

Output

Country Total_Male_Employees
Canada 2
Brazil 1
Japan 1

The following query returns the number of male and female employees.
We group the rows that have the same gender, and then we count the number of rows in each group.

Example 5

SELECT gender AS 'Gender', COUNT(*) AS 'Total Employees'
FROM employees
GROUP BY country;
    

Output

Gender Total Employees
Female 6
Male 4

The following query returns the average salary in each country.
We group the rows that have the same country, and then we calculate the average salary in each group.

Example 6

SELECT country AS 'Country', AVG(salary) AS 'Average Salaries'
FROM employees
GROUP BY country;
    

Output

Country Average Salaries
Canada 800.000000
Brazil 900.000000
Denmark 816.666667
Australia 1000.000000
Germany 847.500000
France 700.000000
Japan 880.000000

The following query returns the number of employees and the total salaries in each country.
We group the rows that have the same country, and then we count the number and the sum of salaries in each group.

Example 7

SELECT country AS 'Country', COUNT(id) AS 'Total Employees', SUM(salary) AS 'Total Salaries'
FROM employees
GROUP BY country;
    

Output

Country Total Employees Total Salaries
Denmark 1 800.00
Australia 1 900.00
Canada 3 2450.00
Germany 1 1000.00
Brazil 2 1695.00
France 1 700.00
Japan 1 880.00

Group By Multiple Column

The following query returns the number of male and female employees in each country.
First, we group the rows that have the same country, and then we group them again based on their genders, and then we count the number of rows in each gender. At the end, we sort the results based on country names.

Example

SELECT country AS 'Country', gender AS 'Gender', COUNT(id) AS 'Total Employees'
FROM employees
GROUP BY country, gender
ORDER BY country;
    

Output

Country Gender Total Employees
Australia female 1
Brazil female 1
Brazil male 1
Canada female 1
Canada male 2
Denmark female 1
France female 1
Germany female 1
Japan male 1

Note: Brazil and Canada are repeated because they have male and female employees.


Group By Exercise

1- Write a query that creates a new database called "training".
Note: you should recreate it if it already exists.

2- Write a query that creates a table called "users" and check whether it exists or not. the table should contain the following fields:

  • id INT NOT NULL PRIMARY KEY AUTO_INCREMENT
  • username VARCHAR(50)
  • role VARCHAR(20)
  • join_date DATE

3- Write a query that inserts 10 rows in the "users" table.
Note: roles should be "admin", "editor", "writer" or "subscriber".

4- Write a query that returns how many users are in each role in the "users" table in ascending order.


Solution

DROP DATABASE IF EXISTS training;

CREATE DATABASE training;

USE training;

CREATE TABLE IF NOT EXISTS users (
	id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50),
    role VARCHAR(20),
    join_date DATE
);

INSERT INTO users (username, role, join_date) VALUES
('Masha', 'admin', '2020-02-01'),
('Adam', 'editor', '2020-02-01'),
('Moly', 'subscriber', '2020-02-03'),
('Sandra', 'writer', '2020-02-04'),
('Lili', 'subscriber', '2020-02-04'),
('Moses', 'subscriber', '2020-02-04'),
('Jack', 'subscriber', '2020-02-07'),
('Ali', 'editor', '2020-02-10'),
('Alfred', 'writer', '2020-02-13'),
('Mohamed', 'writer', '2020-02-15');

SELECT role As 'Roles', COUNT(*) AS 'Total_Users'
FROM users
GROUP BY role
ORDER BY Total_Users;
    

Tutorials

Online Tools

Sections

Tutorials
Tools
Posts