8th Feb 2024 20 minutes read 9 Practical Examples of SQL LEFT JOIN Tihomir Babic JOIN Table of Contents LEFT JOIN Basics LEFT JOIN Syntax LEFT JOIN Examples Example 1: Basic LEFT JOIN Example 2: Departments and Employees Example 3: Customers and Orders Example 4: LEFT JOIN with 3 Tables Example 5: ‘Forced’ LEFT JOIN with Three Tables Example 6: LEFT JOIN with WHERE Example 7: WHERE vs. ON in LEFT JOIN Example 8: LEFT JOIN with Alias Example 9: LEFT JOIN with GROUP BY More LEFT JOIN Examples and Resources LEFT JOIN is one of SQL's most common JOINs. Make sure you know all its ins and outs by going through all nine of our real-life LEFT JOIN examples. LEFT JOIN – alongside INNER JOIN – is one of the essential SQL tools you need to work with data from two or more tables. But how and when should you use it? These nine LEFT JOIN examples will point the way. Is this the first time you’ve heard about JOINs? If so, we’ve got you covered with our comprehensive SQL JOINs course. You can learn from scratch about all the SQL JOIN types, different ways of joining two or more tables, and when to use each type of JOIN. You’ll even learn how to self-join a table and how to use non-equi joins. By the end of the course, you’ll have solved 99 interactive challenges. LEFT JOIN Basics LEFT JOIN is one of several types of SQL JOINs. The purpose of JOINs is to get the data from two or more tables. LEFT JOIN achieves that goal by returning all the data from the first (left) table and only the matching rows from the second (right) table. The non-matched values from the right table will be shown as NULL. How is this different from other JOINs? Here’s a short overview, but for an even better understanding, have a look at these SQL JOIN examples. INNER JOIN – Returns only the matching rows from the joined tables. Here’s an article for learning more about INNER JOIN. RIGHT JOIN – Returns all the data from the right table and only the matching rows from the left table. The non-matching rows’ values will be NULL. FULL JOIN – Returns all rows from both joined tables. If there are unmatched rows between the tables, they’re shown as NULL. You can learn more about it in our article dedicated to FULL JOIN. CROSS JOIN – Returns all the combinations of all the rows from the joined tables, i.e., a Cartesian product. More information is available in this CROSS JOIN article. LEFT JOIN is the same as LEFT OUTER JOIN. So, yes, LEFT JOIN is an outer type of join, along with RIGHT JOIN and FULL JOIN. As SQL users, we usually write just LEFT JOIN. The reason? It’s shorter, and we’re lazy. You can learn more in the article explaining how LEFT JOIN works. LEFT JOIN Syntax The LEFT JOIN syntax is as follows. SELECT … FROM table1 LEFT JOIN table2 ON table1.column = table2.column; The two key points are the keyword LEFT JOIN and the ON joining clause. The first joined table is referenced in the FROM clause, then the LEFT JOIN is added, followed by the second table you want to join. The tables are joined on matching column values; you reference these columns in the ON clause and put an equals sign between them. This will join the tables where the column from one table is equal to the column from the second table. This is the most common type of LEFT JOIN. It’s called equi-join because of the equals sign. Other comparison operators can be used; these are the non-equi joins and are outside of this article's scope. All this is also explained in our SQL JOIN Cheat Sheet. Keep it close during the following examples; it will help you understand them better. LEFT JOIN Examples Let me now show you several real-life examples of using LEFT JOIN. I’ll kick off with a basic, straightforward example to show you how LEFT JOIN works on real data. Example 1: Basic LEFT JOIN I’ll work with two tables. The first is company, which stores a list of electronics companies. Use this script to create the table. idcompany_name 1Lenovo 2Apple 3Samsung 4Huawei 5Fairphone The second table is the product table. The script for creating the table is here. idproduct_namecompany_id 1Fairphone 45 2Galaxy S24 Ultra3 3Galaxy Z Flip53 4iPhone 15 Pro2 5Fairbuds XL5 6MacBook Pro 16' M3 Pro2 7iPad Air 10.9' M12 8Galaxy Tab S9 FE+3 Let’s LEFT JOIN these two tables and see what happens: SELECT company_name, product_name FROM company LEFT JOIN product ON company.id = product.company_id ORDER BY company_name; I select the company and product name. These are the columns from two tables. So, I need to join the tables to get those columns in the output. The left table is company, and I reference it in FROM. Then I add the LEFT JOIN and the second table, which is product. In the ON clause, I specify the columns on which the tables will be joined. In this case, it’s the column id from the first and the column company_id from the second table. I used ORDER BY to make the output more readable. (You don’t need ORDER BY for the join to work.) Speaking of output, here it is. company_nameproduct_name AppleiPhone 15 Pro AppleiPad Air 10.9' M1 AppleMacBook Pro 16' M3 Pro FairphoneFairphone 4 FairphoneFairbuds XL HuaweiNULL LenovoNULL SamsungGalaxy Z Flip5 SamsungGalaxy S24 Ultra SamsungGalaxy Tab S9 FE+ The output shows a list of all the companies, which is in line with the LEFT JOIN showing all the data from the left table. When one company has multiple products, all these products are listed and the company's name is duplicated. When there are no products by the company (Huawei and Lenovo), the product_name column’s value is NULL. Example 2: Departments and Employees Let’s explore a common scenario. In this example, you want to list all the departments and their employees but also show the departments without employees, if there are such. To achieve that, you need LEFT JOIN. Here’s the table department and its script. It’s a list of departments. iddepartment_name 1Sales 2Accounting 3IT 4HR 5Operations The second table is employee, which is a list of employees. Here’s its script. idfirst_namelast_namedepartment_id 1BobEstevez3 2FrancescaGotze2 3FrankGordon2 4MilicentJohnson3 5HansHandkeNULL 6KatieKeaton1 7LucaDi FrancescoNULL 8ZoeJong1 9PatrickRose2 10BillieThompsonNULL The NULL values here mean that this employee hasn’t been assigned a department yet. To show departments and their employees – as well as departments with no employees – this is the code: SELECT department.id AS department_id, department_name, employee.id AS employee_id, first_name, last_name FROM department LEFT JOIN employee ON department.id = employee.department_id ORDER BY department_id, employee_id; I select the ID from the table department and rename it as department_id. The second selected column from the same table is department_name. The data selected from the employee table is the id (renamed employee_id) and the employees’ names. All this renaming of the columns is just to make the output easier to read. Now, I can reference the table department in FROM and LEFT JOIN it with the table employee. The tables are joined where the department IDs are equal. Finally, I sort the output by the department and then by the employee ID to make it more readable. Here’s the result: department_iddepartment_nameemployee_idfirst_namelast_name 1Sales6KatieKeaton 1Sales8ZoeJong 2Accounting2FrancescaGotze 2Accounting3FrankGordon 2Accounting9PatrickRose 3IT1BobEstevez 3IT4MilicentJohnson 4HRNULLNULLNULL 5OperationsNULLNULLNULL The output shows all the departments and their employees. It also shows two departments that don’t have employees: HR and Operations. It might be that the database hasn’t been updated yet and the new employees are not allocated to the department. Example 3: Customers and Orders Another typical LEFT JOIN example is when you want to find all the customers and their orders – but you also want to include the customers who haven’t placed any orders yet. For that example, I will use the following dataset. The first table is customer, which is a simple list of customers. Here’s the script. idfirst_namelast_name 1FlorentinusGlöckner 2EmanAdcock 3ErikNyman 4LeebaKubo 5LiasVámos 6LavanyaNikolaev 7RishiPetit 8ChristieFodor 9AndrisLončar 10JulianaHarlan The second table in the dataset is orders. You can create it yourself using this script. This is how I write the code to achieve the desired result: SELECT customer.first_name, customer.last_name, orders.id AS order_id, orders.order_date FROM customer LEFT JOIN orders ON customer.id = orders.customer_id; I select the customers' names from the table customer. Logically, the information about the orders comes from the table orders. The left table is customer, and I want all its rows. I LEFT JOIN it with the table orders on the customer ID. The output looks like this: first_namelast_nameorder_idorder_date LiasVámos12024-01-01 EmanAdcock22024-01-08 ChristieFodor32024-01-08 AndrisLončar42024-01-12 LiasVámos52024-01-18 LavanyaNikolaev62024-01-22 JulianaHarlanNULLNULL LeebaKuboNULLNULL FlorentinusGlöcknerNULLNULL ErikNymanNULLNULL RishiPetitNULLNULL You can see it shows all the customers and their orders. Where the customer doesn’t have any orders, there are NULLs. For more practice, take a look at this article demonstrating four more LEFT JOIN examples. Example 4: LEFT JOIN with 3 Tables This is a LEFT JOIN example where I’ll show you how to join three tables. Let’s first have a look at the dataset. The first table is writer, with the script here. It’s simply a list of writers. idfirst_namelast_name 1BernardineEvaristo 2AlbertCamus 3GeorgeOrwell 4ÉmileZola 5MilanKundera 6CharlesDickens 7BohumilHrabal 8WitoldGombrowicz The second table is translator. It’s a list of book translators. The script for creating the table is here. idfirst_namelast_name 1JenniferCroft 2PeterConstantine 3EwaldOsers The final table is book, which shows info about the particular books. Here’s the script. idbook_titlepublication_yearwriter_idtranslator_id 1The Plague200823 2Cosmos201581 3Manifesto: On Never Giving Up20211NULL 4Girl, Woman, Other20191NULL 5The Stranger202223 6Germinal201243 7198420203NULL If the value in the translator_id column is NULL, this book is not a translation. In this example, I want to show all the writers, no matter if they have a book or not. I also want to show the info about the book translator. Here’s what the code should look like: SELECT writer.first_name AS writer_first_name, writer.last_name AS writer_last_name, book_title, translator.first_name AS translator_first_name, translator.last_name AS translator_last_name FROM writer LEFT JOIN book ON writer.id = book.writer_id LEFT JOIN translator ON book.translator_id = translator.id; I select the writers’ names, the titles of their books, and the translators’ names. To get all this data, I need to join all three tables. Joining three (or more) tables is done in the form of a chain. After you join the first two tables, you then add another join, reference the third table, and state the joining condition in the second ON clause. First, I reference the table writer, and LEFT JOIN it with the table book on the writer ID. Then, I add the second LEFT JOIN. I use it to join the second table (book) with the table translator on the translator ID. Why are these LEFT JOINs the result of the relationship between the tables? The first LEFT JOIN is there because there might be writers without a book. However, this is also true for the relationship between the tables book and translator: a book might or might not be a translation, so it might or might not have a corresponding translator. So, you need to use the LEFT JOIN between them, too, because you want to show the books whether or not they are translations. Here’s the code output: writer_first_namewriter_last_namebook_titletranslator_first_nametranslator_last_name AlbertCamusThe PlagueEwaldOsers WitoldGombrowiczCosmosJenniferCroft BernardineEvaristoManifesto: On Never Giving UpNULLNULL BernardineEvaristoGirl, Woman, OtherNULLNULL AlbertCamusThe StrangerEwaldOsers ÉmileZolaGerminalEwaldOsers GeorgeOrwell1984NULLNULL MilanKunderaNULLNULLNULL CharlesDickensNULLNULLNULL BohumilHrabalNULLNULLNULL As you can see, Bernardine Evaristo’s books are shown despite them not being translations. This is because I used LEFT JOIN as a second join. Also, Milan Kundera, Charles Dickens, and Bohumil Hrabal are shown despite not having any books and, therefore, no translators. Example 5: ‘Forced’ LEFT JOIN with Three Tables Usually the choice of LEFT JOIN comes from the nature of the table relationships. However, sometimes we’re “forced” to use the LEFT JOIN. You’ll soon see what I mean. The first table in the dataset is a list of directors named director. Here’s the script. idfirst_namelast_name 1StanleyKubrick 2CélineSciamma 3WoodyAllen 4LynneRamsay 5KrzysztofKieślowski Next is the table streaming_platform, which is a list of available streaming platforms. You can create the table using this script. idplatform_name 1Netflix 2HBO 3Hulu 4Mubi 5Apple TV The third table is streaming_catalogue. It holds information about movies and has relationships with the first two tables via director_id and streaming_platform_id. Here’s the script to create the table. idmovie_titlerelease_yeardirector_idstreaming_platform_idstarted_showingended_showing 1Three Colours: Blue1993542023-02-282023-09-30 2Three Colours: White1994542023-02-282023-09-30 3Three Colours: Red1994542023-02-282023-09-30 4Manhattan Murder Mystery1993312023-08-15NULL 5Portrait of a Lady on Fire2019212023-01-012023-09-28 6Three Colours: Blue1993522024-01-15NULL 7Three Colours: White1994522024-01-15NULL 8Three Colours: Red1994522024-01-15NULL 9Tomboy2011212020-04-012021-04-01 10Vicky Cristina Barcelona2008312023-10-01NULL The NULL values in the ended_showing column mean that the movie is still being shown on the platform. I want to show all the directors, their movies, and the streaming platforms that are showing (or have shown) their movies. Also, I want to show the directors who don’t have any movies streaming. The relationship between the tables is that every movie has to have a director, but not vice versa. Also, every movie in the catalog has to have a streaming platform, but not every streaming platform has to be in the catalog. I start writing the code by selecting the directors’ names, movie titles, platform names, and the showing start and end dates. From the previous examples, you know that it’s expected to join the table director with the table streaming_catalogue on the director ID column. This is what I do to ensure I also show the directors who don’t have any movies in the catalog. Now, I add the second LEFT JOIN to join the streaming_catalogue table with the streaming_platform table on the platform ID. SELECT first_name AS director_first_name, last_name AS director_last_name, movie_title, platform_name, started_showing, ended_showing FROM director LEFT JOIN streaming_catalogue ON director.id = streaming_catalogue.director_id LEFT JOIN streaming_platform ON streaming_catalogue.streaming_platform_id = streaming_platform.id; The query returns this output: director_first_namedirector_last_namemovie_titleplatform_namestarted_showingended_showing KrzysztofKieślowskiThree Colours: BlueMubi2023-02-282023-09-30 KrzysztofKieślowskiThree Colours: WhiteMubi2023-02-282023-09-30 KrzysztofKieślowskiThree Colours: RedMubi2023-02-282023-09-30 WoodyAllenManhattan Murder MysteryNetflix2023-08-15NULL CélineSciammaPortrait of a Lady on FireNetflix2023-01-012023-09-28 KrzysztofKieślowskiThree Colours: BlueHBO2024-01-15NULL KrzysztofKieślowskiThree Colours: WhiteHBO2024-01-15NULL KrzysztofKieślowskiThree Colours: RedHBO2024-01-15NULL CélineSciammaTomboyNetflix2020-04-012021-04-01 WoodyAllenVicky Cristina BarcelonaNetflix2023-10-01NULL LynneRamsayNULLNULLNULLNULL StanleyKubrickNULLNULLNULLNULL The output shows all the directors, their movies, and the platforms where they are or were showing. The movies with all the data except a NULL in the ended_showing columns can still be seen on a particular platform. Despite there being no movies in the catalog, Lynne Ramsay and Stanley Kubrick are also listed. This is recognized by having their names but no other data. I was able to get them because I used two LEFT JOINs. The first LEFT JOIN is not questionable; I had to use it in case there are directors without movies. It turns out there are. But what about the second LEFT JOIN? I was kind of forced to use it to retain all those directors without the movies and get the desired output. Why ‘forced’? Well, let’s use INNER JOIN instead of the second LEFT JOIN, and you’ll see. SELECT first_name AS director_first_name, last_name AS director_last_name, movie_title, platform_name, started_showing, ended_showing FROM director LEFT JOIN streaming_catalogue ON director.id = streaming_catalogue.director_id JOIN streaming_platform ON streaming_catalogue.streaming_platform_id = streaming_platform.id; The output is now missing Lynne Ramsay and Stanley Kubrick! director_first_namedirector_last_namemovie_titleplatform_namestarted_showingended_showing KrzysztofKieślowskiThree Colours: BlueMubi2023-02-282023-09-30 KrzysztofKieślowskiThree Colours: WhiteMubi2023-02-282023-09-30 KrzysztofKieślowskiThree Colours: RedMubi2023-02-282023-09-30 WoodyAllenManhattan Murder MysteryNetflix2023-08-15NULL CélineSciammaPortrait of a Lady on FireNetflix2023-01-012023-09-28 KrzysztofKieślowskiThree Colours: BlueHBO2024-01-15NULL KrzysztofKieślowskiThree Colours: WhiteHBO2024-01-15NULL KrzysztofKieślowskiThree Colours: RedHBO2024-01-15NULL CélineSciammaTomboyNetflix2020-04-012021-04-01 WoodyAllenVicky Cristina BarcelonaNetflix2023-10-01NULL Why is that? Because INNER JOIN returns only the matching rows from the joined tables. So, I was able to output the directors without movies with the first LEFT JOIN. Well done me! But then I used INNER JOIN and messed everything up! INNER JOIN cancels out the first LEFT JOIN, as it will show only the matching rows between streaming_catalogue and streaming_platform. Since Lynne Ramsay and Stanley Kubrick have no movies in the table streaming_catalogue, their non-existing movies can’t be matched in the streaming_platform table and they don’t appear in the final result. Here’s an article that provides more tips and examples for LEFT JOINing multiple tables. Example 6: LEFT JOIN with WHERE Let’s continue the SQL LEFT JOIN examples using the same data as in the previous one. This example will show you how LEFT JOIN can be used with the WHERE clause. The code below does exactly that to find the directors, their movies, and the start and end dates of the showings. However, it doesn’t show all the movies – only those whose showing ended before 1 October 2023. SELECT first_name, last_name, movie_title, started_showing, ended_showing FROM director LEFT JOIN streaming_catalogue ON director.id = streaming_catalogue.director_id WHERE ended_showing < '2023_10_01'; After selecting the necessary columns, I LEFT JOIN the table director with the table streaming_ catalogue. The tables are joined on the director ID. I use the WHERE clause to output only the movies that ended showing before 1 October 2023. In WHERE I compare the ended_showing column with the required cut-off date using the comparison operator ‘less than’ (<). Here’s the output. No movie ended showing after 1 October 2023. first_namelast_namemovie_titlestarted_showingended_showing KrzysztofKieślowskiThree Colours: Blue2023-02-282023-09-30 KrzysztofKieślowskiThree Colours: White2023-02-282023-09-30 KrzysztofKieślowskiThree Colours: Red2023-02-282023-09-30 CélineSciammaPortrait of a Lady on Fire2023-01-012023-09-28 CélineSciammaTomboy2020-04-012021-04-01 Example 7: WHERE vs. ON in LEFT JOIN I will now show you how the effect of the LEFT JOIN can be canceled if WHERE is used on the right table. And, of course, I will show you a remedy for that. I’m again using the same dataset as in the previous example. Let’s say I want to query it and retrieve all the directors whether they have a movie in the database or not. For those directors that have a movie, I want to show only movies that were released in 1993. I might try to achieve that by writing this query: SELECT DISTINCT first_name, last_name, movie_title, release_year FROM director LEFT JOIN streaming_catalogue ON director.id = streaming_catalogue.director_id WHERE release_year = 1993; First, I select the necessary columns. I’m using SELECT DISTINCT to avoid row duplication, as there are some movies that appear more than once in the table streaming_catalogue. Now, I LEFT JOIN the table director with streaming_catalogue on the director ID. The final step would be to use the WHERE clause and retrieve only movies released in 1993. Let’s see the output: first_namelast_namemovie_titlerelease_year KrzysztofKieślowskiThree Colours: Blue1993 WoodyAllenManhattan Murder Mystery1993 Nope, this is not right! I got only two directors instead of five. Remember, I wanted a list of all the directors. Why did this happen, despite my using LEFT JOIN? The reason is that when the filter in WHERE is applied to data from the right table, it cancels out the effect of LEFT JOIN. Remember, if the director doesn’t have any movies in the table, then the values in the column release_year will be NULL. It’s the result of LEFT JOIN. And the filter in WHERE will exclude NULLs, too, from the output. So, how can you then list all the directors and use the filter on the release year at the same time? The answer is you should move the filtering condition from WHERE to ON, like this. SELECT DISTINCT first_name, last_name, movie_title, release_year FROM director LEFT JOIN streaming_catalogue ON director.id = streaming_catalogue.director_id AND release_year = 1993; The release year condition now becomes the second joining condition in the ON clause. The second (third, fourth…) condition is added using the keyword AND. Look, the output is now correct: first_namelast_namemovie_titlerelease_year StanleyKubrickNULLNULL LynneRamsayNULLNULL CélineSciammaNULLNULL KrzysztofKieślowskiThree Colours: Blue1993 WoodyAllenManhattan Murder Mystery1993 You can learn more in this article dedicated to the difference between WHERE and ON in SQL JOINs. Example 8: LEFT JOIN with Alias In all the previous examples, using aliases with the tables in LEFT JOIN was not necessary. It might’ve helped you to shorten the names of the tables and write code a little quicker. Helpful, yes, but not mandatory. However, aliases become mandatory when you’re LEFT JOINING the table with itself – i.e. when you’re self-joining the table. Let’s see how this works in an example where I want to retrieve the names of all the employees and the names of their managers. I want this list to contain employees who don’t have a manager above them. I’ll demonstrate this in the table named employees_managers. Here’s the script: idfirst_namelast_namemanager_id 1LindKaiser2 2IanMcKune8 3DeckTrustrieNULL 4RupertaNind1 5GarrotCharsleyNULL 6AtheneFedoronko8 7PriscillaCrocombeNULL 8StafaniSidebottom8 9MarveTrustie1 10AntonyMarple2 This is a list of the employees. The column manager_id contains the ID of the employee who is the manager of the particular employee. Some employees don’t have managers, so the value is NULL. To complete the required task, I need to write this query: SELECT e.first_name AS employee_first_name, e.last_name AS employee_last_name, m.first_name AS manager_first_name, m.last_name AS manager_last_name FROM employees_managers e LEFT JOIN employees_managers m ON e.manager_id = m.id; I reference the table in the FROM clause and give it the alias e. This table will serve as the employee data. Then, I reference the same table in LEFT JOIN and give it the alias m. It will be used for the managers' data. That way, I was able to join the table with itself. It’s no different than joining two different tables. When self-joining, one table acts as two tables. You only need to give them aliases so that SQL knows which table you refer to. The table is self-joined where the manager ID from the ‘employee’ table equals the employee ID from the ‘manager’ table. That way, I will get all the employees and their managers. Now that I have tables in place, I only need to select the necessary columns. Again, to make a distinction, I use different table aliases to get employees’ and managers’ names. Here’s the output: employee_first_nameemployee_last_namemanager_first_namemanager_last_name LindKaiserIanMcKune IanMcKuneStafaniSidebottom DeckTrustrieNULLNULL RupertaNindLindKaiser GarrotCharsleyNULLNULL AtheneFedoronkoStafaniSidebottom PriscillaCrocombeNULLNULL StafaniSidebottomStafaniSidebottom MarveTrustieLindKaiser AntonyMarpleIanMcKune As you can see, this is a full list of employees and their managers. Deck Trustrie, Garrot Charsley, and Priscilla Crocombe don’t have managers. They are at the top of the company’s hierarchical structure. Example 9: LEFT JOIN with GROUP BY Let’s now go back to Example 2, where we worked with a list of departments and employees. A straightforward example of LEFT JOIN with GROUP BY would be to list all the departments and count the number of employees in each: SELECT department_name, COUNT(employee.id) AS number_of_employees FROM department LEFT JOIN employee ON department.id = employee.department_id GROUP BY department_name; I select the department and use the aggregate function COUNT() on the employee ID column to find the number of employees. The data comes from two tables. I need to LEFT JOIN the department table with the employee table since I also want departments with no employees. The tables are joined on the department ID. Since I used an aggregate function, I also need to group data. I do that by using the GROUP BY clause. Grouping the output by the department name will show the number of employees by each department. Have a look. Neat, right? department_namenumber_of_employees Accounting3 Operations0 Sales2 IT2 HR0 Now, let’s try another example and use COUNT(*) instead of applying COUNT() to a particular column. This time, I’m using the data about the companies and their products from Example 1. In this example, I want to retrieve all the companies and show the number of products they have. Let’s see what happens if I use COUNT(*): SELECT company_name, COUNT(*) AS number_of_products FROM company LEFT JOIN product ON company.id = product.company_id GROUP BY company_name; The tables company and product are LEFT JOINed on the company ID. I’m using COUNT(*) and GROUP BY to find the number of products by company. This is the output: company_namenumber_of_products Huawei1 Lenovo1 Samsung3 Apple3 Fairphone2 However, I can tell you this output is not right: Huawei and Lenovo should’ve had zero products. Why did this mistake occur? The culprit is COUNT(*)! The asterisk in the COUNT() function means it counts all the rows, including NULLs. Is it getting clearer now? Yes, that’s right: when the companies without products are LEFT JOINed, they will have NULL products. However, this is still a value, and COUNT(*) will see every NULL value as one product. In other words, even the companies without products will be shown as having one product. To fix this, use COUNT(expression). In this case, it means COUNT(product.id). Using COUNT() with a column name ignores NULLs: SELECT company_name, COUNT(product.id) AS number_of_products FROM company LEFT JOIN product ON company.id = product.company_id GROUP BY company_name; The output is now as expected: company_namenumber_of_products Huawei0 Lenovo0 Samsung3 Apple3 Fairphone2 You can go into more detail by reading this article about different variations of the COUNT() aggregate function. More LEFT JOIN Examples and Resources You can see from the above examples that LEFT JOIN has wide use in practical work with data. It can be used for simple data retrieval where you need all the data from one table and only the matching data from another. However, it can also be used when joining multiple tables, with WHERE, in self-joins, and with aggregate functions and GROUP BY. SQL joins are vital in working with multiple tables, which is an everyday task even for junior data analysts. Knowing joins is an absolute must if you want to consider yourself fluent in SQL and improve in your job. This also means knowing LEFT JOIN, as it’s one of the two most used join types. Due to its very specific characteristics, many tasks can’t be done other than by leveraging LEFT JOIN. So, if you need an in-depth guide through these topics, we invite you to take a look at our SQL JOINs course. Tags: JOIN