Summary: in this tutorial, you’ll learn how to use PostgreSQL INNER JOIN
to merge rows from two tables and select the matching rows
Introduction to PostgreSQL INNER JOIN clause
In PostgreSQL, a database consists of multiple related tables. They link to each other via foreign keys.
To select data from two or more tables, you use the INNER JOIN
clause of the SELECT
statement.
Here’s the syntax for the INNER JOIN
clause:
SELECT
table1.column1,
table2.column2,
...
FROM
table1
INNER JOIN table2 ON table1.column1 = table2.column1
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
In this syntax:
- First, specify the name of the first table (
table1
) in theFROM
clause. - Second, provide the name of the second table (
table2
) you want to join in theINNER JOIN
clause. - Third, use a condition to match rows from the first table (
table1
) with the second table (table2
) in theON
clause. The condition matches rows in both tables by comparing the values ofcolumn1
intable1
with the values ofcolumn1
intable2
. - Finally, list out the columns from both tables to include in the final result set in the
SELECT
clause.
PostgreSQL evaluates the FROM
clause first, then the INNER JOIN
clause, and finally the SELECT
clause.
Here’s how PostgreSQL inner join works:
- First, for each row in the
table1
, theINNER JOIN
compares the value incolumn1
with the value ofcolumn1
of each row in thetable2
. - Second, include both rows in an intermediate table if they are equal.
- Third, select the columns specified in the
SELECT
clause in the final result set.
PostgreSQL Inner Join example
Suppose you have two tables: products
and brands
:
CREATE TABLE brands (
brand_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
CREATE TABLE products (
product_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
brand_id INT NOT NULL,
FOREIGN KEY (brand_id) REFERENCES brands (brand_id)
);
INSERT INTO
brands (name)
VALUES
('Apple'),
('Samsung'),
('Google')
RETURNING *;
INSERT INTO
products (name, price, brand_id)
VALUES
('iPhone 14 Pro', 999.99, 1),
('iPhone 15 Pro', 1199.99, 1),
('Galaxy S23 Ultra', 1149.47, 2)
RETURNING *;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
The products
table has a foreign key column, brand_id
, that links to the brand_id
primary key column of the brands
table:
The brands
table:
brand_id | name |
---|---|
1 | Apple |
2 | Samsung |
3 |
The products
table:
product_id | name | price | brand_id |
---|---|---|---|
1 | iPhone 14 Pro | 999.99 | 1 |
2 | iPhone 15 Pro | 1299.99 | 1 |
3 | Galaxy S23 Ultra | 1149.47 | 2 |
To select the product name and price from the products
table and the brand name from the brands
table, you use the following statement:
SELECT
products.name,
products.price,
brands.name
FROM
products
INNER JOIN brands ON brands.brand_id = products.brand_id;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Output:
name | price | name
------------------+---------+---------
iPhone 14 Pro | 999.99 | Apple
iPhone 15 Pro | 1199.99 | Apple
Galaxy S23 Ultra | 1149.47 | Samsung
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
How the query works.
First, the FROM
clause examines each row from the products
table.
Second, the INNER JOIN
clause compares the brand_id
of each row in the products
table with the brand_id
of each row in the brands
table. Since they have the same brand_id
, the query will combine rows from both into a imagined table:
product_id | name | price | brand_id | brand_id | name |
---|---|---|---|---|---|
1 | iPhone 14 Pro | 999.99 | 1 | 1 | Apple |
2 | iPhone 15 Pro | 1299.99 | 1 | 1 | Apple |
3 | Galaxy S23 Ultra | 1149.47 | 2 | 2 | Samsung |
In more detail:
- Row 1 and 2 of the
products
table matches row 1 in thebrands
table. - Row 3 in the
products
table matches row 2 of thebrands
table.
Third, the SELECT
clause selects the name
and price
columns from the products
table and name
columns of the brands
table:
name | price | name |
---|---|---|
iPhone 14 Pro | 999.99 | Apple |
iPhone 15 Pro | 1299.99 | Apple |
Galaxy S23 Ultra | 1149.47 | Samsung |
Qualifying column names
Since both tables products
and brands
have the same name
and brand_id
columns, we have to reference them using the following syntax:
table_name.column_name
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
If we don’t do so, PostgreSQL will issue an ambiguous error. For example:
SELECT
name,
price,
name
FROM
products
INNER JOIN brands ON products.brand_id = products.brand_id;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Error:
column reference "name" is ambiguous
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
The output has two columns with the same name (name
); we can use column aliases to make it more obvious:
SELECT
products.name product_name,
products.price,
brands.name brand_name
FROM
products
INNER JOIN brands ON brands.brand_id = products.brand_id;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Output:
product_name | price | brand_name
------------------+---------+------------
iPhone 14 Pro | 999.99 | Apple
iPhone 15 Pro | 1199.99 | Apple
Galaxy S23 Ultra | 1149.47 | Samsung
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Joining tables with table aliases
Typing the same table names for every column is tedious. PostgreSQL supports temporary names for tables in a query using table aliases.
Like a column alias, you can assign an alias to a table temporarily during the query execution using the following syntax:
table_name AS table_alias
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Since the AS
keyword is optional, you can ignore it like this:
table_name table_alias
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
The following statement joins the products
table with the brands
table using table aliases:
SELECT
p.name product_name,
p.price,
b.name brand_name
FROM
products AS p
INNER JOIN brands AS b ON b.brand_id = p.brand_id;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
In this example, we assign p
as the table alias for the products
table and b
as the table alias for the brands
table. Then, we use these table aliases to reference the column’s names from both tables.
The USING syntax
If you join two tables by comparing values from the same column names using the equal operator (=
), you can use the USING
clause syntax:
SELECT table1.column1, table2.column2, ...
FROM table1
INNER JOIN table2 USING (column1);
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
In this syntax, we replace the following ON
clause:
ON table1.column1 = table2.column1
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
with the USING
clause:
USING (column1)
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
For example, the following statement joins the products
table with the brands
table using the USING
clause:
SELECT
p.name product_name,
p.price,
b.name brand_name
FROM
products p
INNER JOIN brands b USING (brand_id);
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
In this statement, we don’t use the AS
keyword for the table aliases and use the USING
clause instead of the ON
clause.
Summary
- Use the
INNER JOIN
clause to merge rows from multiple tables and select the matching rows. - Table aliases are temporary table names during the query execution.
- Use the
USING
syntax when two tables have the same column names, and you want to join them on those columns to make the statement more concise.