{"id":27127,"date":"2022-12-12T15:17:48","date_gmt":"2022-12-12T23:17:48","guid":{"rendered":"https:\/\/coderpad.io\/?p=27127"},"modified":"2023-06-05T13:47:31","modified_gmt":"2023-06-05T20:47:31","slug":"mysql-join-clause-a-detailed-guide","status":"publish","type":"post","link":"https:\/\/coderpad.io\/blog\/development\/mysql-join-clause-a-detailed-guide\/","title":{"rendered":"MySQL JOIN Clause: A Detailed Guide"},"content":{"rendered":"\n<p>MySQL joins undoubtedly belongs to the <a href=\"https:\/\/coderpad.io\/blog\/development\/sql-functions-and-techniques-every-data-person-should-know\/\">list of database techniques everyone should know.<\/a> After all, a common need when using a relational database is to combine data from more than one table, creating a cohesive result. In today&#8217;s post, we&#8217;ll cover the JOIN clause in MySQL.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Requirements<\/h2>\n\n\n\n<p>We&#8217;ll start the post by covering what joins are in MySQL, and then we&#8217;ll quickly move on to the practical part. To follow along with that second part, you&#8217;ll need the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A MySQL instance installed and running on your machine (the <a href=\"https:\/\/hub.docker.com\/_\/mysql\" target=\"_blank\" rel=\"noopener\">Docker image<\/a>&nbsp;is a great way to achieve that)<\/li>\n\n\n\n<li>Any MySQL client to connect to said instance<\/li>\n<\/ul>\n\n\n\n<p>We also assume basic database knowledge. Let&#8217;s begin!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What are joins in MySQL?<\/h2>\n\n\n\n<p>In SQL language, the JOIN clause is what you use to combine data from two or more tables. We can make things more straightforward with an example. Imagine a database for an e-commerce system with a <code>categories<\/code>&nbsp;table:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th scope=\"col\"><strong>id<\/strong><\/th><th scope=\"col\"><strong>description<\/strong><\/th><\/tr><\/thead><tbody><tr><td>1<\/td><td>Toys<\/td><\/tr><tr><td>2<\/td><td>Clothing<\/td><\/tr><tr><td>3<\/td><td>Technology<\/td><\/tr><tr><td>4<\/td><td>Food &amp; Beverages<\/td><\/tr><tr><td>5<\/td><td>Books<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>The database also contains a <code>products<\/code>&nbsp;table:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">| id | \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 description\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 | category_id | \u00a0 | \u00a0 |\n\n|:--:|:------------------------------:|:-----------:|---|---|\n\n| <span class=\"hljs-number\">7<\/span>\u00a0 | Notebook Dell Inspiron \u00a0 \u00a0 \u00a0 \u00a0 | <span class=\"hljs-number\">3<\/span> \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 | \u00a0 | \u00a0 |\n\n| <span class=\"hljs-number\">9<\/span>\u00a0 | iPhone <span class=\"hljs-number\">14<\/span> Pro\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 | <span class=\"hljs-number\">3<\/span> \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 | \u00a0 | \u00a0 |\n\n| <span class=\"hljs-number\">10<\/span> | iPhone <span class=\"hljs-number\">14<\/span> Pro Max\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 | <span class=\"hljs-number\">3<\/span> \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 | \u00a0 | \u00a0 |\n\n| <span class=\"hljs-number\">26<\/span> | Super Awesome Coffee \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 | <span class=\"hljs-number\">4<\/span> \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 | \u00a0 | \u00a0 |\n\n| <span class=\"hljs-number\">37<\/span> | <span class=\"hljs-string\">\"Refactoring\"<\/span> By Martin Fowler | <span class=\"hljs-number\">5<\/span> \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 | \u00a0 | \u00a0 |<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>As you can see, the <code>products<\/code>&nbsp;table has a column called <code>category_id<\/code>,&nbsp;whose value for each row references a given row from the <code>categories<\/code>&nbsp;table. This is what we call a &#8220;foreign key relationship,&#8221; and through that relationship, we can perform a join between the two tables to display\u2014for instance\u2014a list of products along with their categories:&nbsp;<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">| \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Product\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 |\u00a0 \u00a0 \u00a0 Category \u00a0 \u00a0 | \u00a0 | \u00a0 | \u00a0 |\n\n|:------------------------------:|:-----------------:|---|---|---|\n\n| Notebook Dell Inspiron \u00a0 \u00a0 \u00a0 \u00a0 | Technology\u00a0 \u00a0 \u00a0 \u00a0 | \u00a0 | \u00a0 | \u00a0 |\n\n| iPhone <span class=\"hljs-number\">14<\/span> Pro\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 | Technology\u00a0 \u00a0 \u00a0 \u00a0 | \u00a0 | \u00a0 | \u00a0 |\n\n| iPhone <span class=\"hljs-number\">14<\/span> Pro Max\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 | Technology\u00a0 \u00a0 \u00a0 \u00a0 | \u00a0 | \u00a0 | \u00a0 |\n\n| Super Awesome Coffee \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 | Foods &amp; Beverages | \u00a0 | \u00a0 | \u00a0 |\n\n| <span class=\"hljs-string\">\"Refactoring\"<\/span> By Martin Fowler | Books \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 | \u00a0 | \u00a0 | \u00a0 |<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>By this point, it&#8217;s possible that the following question has crossed your mind: Why don&#8217;t we put everything on the same table? That would eliminate the need for joins!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why do we need MySQL joins?<\/h2>\n\n\n\n<p>We need joins because we split related data into multiple tables, and <em>that<\/em> is due to <a href=\"https:\/\/en.wikipedia.org\/wiki\/Database_normalization\" target=\"_blank\" rel=\"noopener\">database normalization.<\/a><\/p>\n\n\n\n<p>Database normalization, in the simplest possible terms, is a technique we use to eliminate data redundancy. Basically, we strive for every piece of data on our database to have a single instance. That way, we guarantee data integrity. Normalization also helps keeping storage costs down, because you don\u2019t have to store many (potentially thousands or even millions) copies of the same piece of data.&nbsp;<\/p>\n\n\n\n<p>For example, suppose that in the previous examples, we didn&#8217;t have the <code>categories<\/code>&nbsp;table, having instead a <code>category<\/code>&nbsp;column on the <code>products<\/code>&nbsp;table that contained the category&#8217;s description. In this scenario, we would end up with the same category potentially listed several times, threatening data integrity. There could have been typos. We might have needed to update some category descriptions and then failed to update all rows accordingly, leaving the old name in several places.<\/p>\n\n\n\n<p>With the categories belonging to a dedicated table, we ensure a <strong>canonical<\/strong> place for each category to which related tables can link if needed. If there&#8217;s a need to update, that happens once and in just one place.<\/p>\n\n\n\n<p>In summary: even though it might seem odd and unintuitive for humans, splitting data across multiple tables is a great way for computer to organize data, in a fast, efficient way while ensuring data integrity.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Types of MySQL joins<\/h2>\n\n\n\n<p>There are three main types of MySQL joins:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Inner join<\/li>\n\n\n\n<li>Outer join (which has subtypes)<\/li>\n\n\n\n<li>Cross join<\/li>\n<\/ul>\n\n\n\n<p>Let&#8217;s cover each type so you can learn how they work and which problems they solve.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Setting up the database<\/h3>\n\n\n\n<p>Using your favorite client, connect to your MySQL database and run the following query:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"SQL (Structured Query Language)\" data-shcb-language-slug=\"sql\"><span><code class=\"hljs language-sql shcb-wrap-lines\"><span class=\"hljs-keyword\">CREATE<\/span> <span class=\"hljs-keyword\">DATABASE<\/span> commerce;\n\n<span class=\"hljs-keyword\">USE<\/span> commerce;\n\n<span class=\"hljs-keyword\">CREATE<\/span> <span class=\"hljs-keyword\">TABLE<\/span> categories (\n\n\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">id<\/span> MEDIUMINT <span class=\"hljs-keyword\">NOT<\/span> <span class=\"hljs-literal\">NULL<\/span> AUTO_INCREMENT,\n\n\u00a0\u00a0\u00a0\u00a0\u00a0description <span class=\"hljs-built_in\">VARCHAR<\/span>(<span class=\"hljs-number\">250<\/span>) <span class=\"hljs-keyword\">NOT<\/span> <span class=\"hljs-literal\">NULL<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0\u00a0PRIMARY <span class=\"hljs-keyword\">KEY<\/span> (<span class=\"hljs-keyword\">id<\/span>)\n\n);\n\n<span class=\"hljs-keyword\">INSERT<\/span> <span class=\"hljs-keyword\">INTO<\/span> categories (description) <span class=\"hljs-keyword\">VALUES<\/span> (<span class=\"hljs-string\">'Toys'<\/span>);\n\n<span class=\"hljs-keyword\">INSERT<\/span> <span class=\"hljs-keyword\">INTO<\/span> categories (description) <span class=\"hljs-keyword\">VALUES<\/span> (<span class=\"hljs-string\">'Clothing'<\/span>);\n\n<span class=\"hljs-keyword\">INSERT<\/span> <span class=\"hljs-keyword\">INTO<\/span> categories (description) <span class=\"hljs-keyword\">VALUES<\/span> (<span class=\"hljs-string\">'Technology'<\/span>);\n\n<span class=\"hljs-keyword\">INSERT<\/span> <span class=\"hljs-keyword\">INTO<\/span> categories (description) <span class=\"hljs-keyword\">VALUES<\/span> (<span class=\"hljs-string\">'Food &amp; Beverages'<\/span>);\n\n<span class=\"hljs-keyword\">INSERT<\/span> <span class=\"hljs-keyword\">INTO<\/span> categories (description) <span class=\"hljs-keyword\">VALUES<\/span> (<span class=\"hljs-string\">'Books'<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">SQL (Structured Query Language)<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">sql<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This will create the <code>categories<\/code>&nbsp;table in the <code>commerce<\/code>&nbsp;database and insert five rows into it.<\/p>\n\n\n\n<p>Now, let&#8217;s create the <code>products<\/code>&nbsp;table:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"SQL (Structured Query Language)\" data-shcb-language-slug=\"sql\"><span><code class=\"hljs language-sql shcb-wrap-lines\"><span class=\"hljs-keyword\">CREATE<\/span> <span class=\"hljs-keyword\">TABLE<\/span> products (\n\n<span class=\"hljs-keyword\">id<\/span> MEDIUMINT <span class=\"hljs-keyword\">NOT<\/span> <span class=\"hljs-literal\">NULL<\/span> AUTO_INCREMENT,\n\n\u00a0\u00a0\u00a0\u00a0description <span class=\"hljs-built_in\">VARCHAR<\/span>(<span class=\"hljs-number\">250<\/span>) <span class=\"hljs-keyword\">NOT<\/span> <span class=\"hljs-literal\">NULL<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0category_id MEDIUMINT <span class=\"hljs-literal\">NULL<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0PRIMARY <span class=\"hljs-keyword\">KEY<\/span> (<span class=\"hljs-keyword\">id<\/span>),\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">FOREIGN<\/span> <span class=\"hljs-keyword\">KEY<\/span> (category_id)\n\n    <span class=\"hljs-keyword\">REFERENCES<\/span> categories(<span class=\"hljs-keyword\">id<\/span>)\n\n    <span class=\"hljs-keyword\">ON<\/span> <span class=\"hljs-keyword\">DELETE<\/span> <span class=\"hljs-keyword\">SET<\/span> <span class=\"hljs-literal\">NULL<\/span>\n);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">SQL (Structured Query Language)<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">sql<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Notice that when creating the foreign key reference, we used the <code>ON DELETE SET NULL<\/code> clause. That means that if we try to delete a row from <code>categories<\/code>&nbsp;with one or more &#8220;children&#8221; in <code>products<\/code>, the deletion will be allowed, and the <code>category_id<\/code>&nbsp;column from the child rows will be updated to <code>null<\/code>. The reason we&#8217;re doing this will become clear soon.<\/p>\n\n\n\n<p>The next step is inserting the products:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"SQL (Structured Query Language)\" data-shcb-language-slug=\"sql\"><span><code class=\"hljs language-sql shcb-wrap-lines\"><span class=\"hljs-keyword\">INSERT<\/span> <span class=\"hljs-keyword\">INTO<\/span> products (description, category_id) <span class=\"hljs-keyword\">VALUES<\/span> (<span class=\"hljs-string\">'Notebook Dell Inspiron'<\/span>, <span class=\"hljs-number\">3<\/span>);\n\n<span class=\"hljs-keyword\">INSERT<\/span> <span class=\"hljs-keyword\">INTO<\/span> products (description, category_id) <span class=\"hljs-keyword\">VALUES<\/span> (<span class=\"hljs-string\">'iPhone 14 Pro'<\/span>, <span class=\"hljs-number\">3<\/span>);\n\n<span class=\"hljs-keyword\">INSERT<\/span> <span class=\"hljs-keyword\">INTO<\/span> products (description, category_id) <span class=\"hljs-keyword\">VALUES<\/span> (<span class=\"hljs-string\">'iPhone 14 Pro Max'<\/span>, <span class=\"hljs-number\">3<\/span>);\n\n<span class=\"hljs-keyword\">INSERT<\/span> <span class=\"hljs-keyword\">INTO<\/span> products (description, category_id) <span class=\"hljs-keyword\">VALUES<\/span> (<span class=\"hljs-string\">'Super Awesome Coffee'<\/span>, <span class=\"hljs-number\">4<\/span>);\n\n<span class=\"hljs-keyword\">INSERT<\/span> <span class=\"hljs-keyword\">INTO<\/span> products (description, category_id) <span class=\"hljs-keyword\">VALUES<\/span> (<span class=\"hljs-string\">'\"Refactoring\" By Martin Fowler'<\/span>, <span class=\"hljs-number\">5<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">SQL (Structured Query Language)<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">sql<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now, we&#8217;re finally ready to start using joins.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Inner join: the basic scenario<\/h3>\n\n\n\n<p>The inner join is arguably the most common type of join you&#8217;ll use in SQL. It consists of joining two tables based on one or more columns from each table matching. Values from both tables are retrieved only when a match occurs. Visually, you could represent an inner join as an intersection between two sets.<\/p>\n\n\n\n<p>Let&#8217;s see a practical example. Since we want the product description and category description, let&#8217;s try to query for that:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">SELECT<\/span> <span class=\"hljs-selector-tag\">p<\/span><span class=\"hljs-selector-class\">.description<\/span> <span class=\"hljs-selector-tag\">Product<\/span>, <span class=\"hljs-selector-tag\">c<\/span><span class=\"hljs-selector-class\">.description<\/span> <span class=\"hljs-selector-tag\">Category<\/span> <span class=\"hljs-selector-tag\">FROM<\/span> <span class=\"hljs-selector-tag\">products<\/span> <span class=\"hljs-selector-tag\">p<\/span>, <span class=\"hljs-selector-tag\">categories<\/span> <span class=\"hljs-selector-tag\">c<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Well, the result doesn&#8217;t look right: It seems that each row from <code>products<\/code>&nbsp;got paired with each row from <code>categories<\/code>:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/12\/img_639724bd5da3f.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">List of products and their categories in the database.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>The explanation is simple: We didn&#8217;t specify how we wanted those rows to match, so MySQL just retrieved every possible combination. Let&#8217;s add a simple <code>WHERE<\/code> clause to our query:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"SQL (Structured Query Language)\" data-shcb-language-slug=\"sql\"><span><code class=\"hljs language-sql shcb-wrap-lines\"><span class=\"hljs-keyword\">SELECT<\/span> p.description Product, c.description <span class=\"hljs-keyword\">Category<\/span> <span class=\"hljs-keyword\">FROM<\/span> products p, categories c <span class=\"hljs-keyword\">where<\/span> p.category_id = c.id<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">SQL (Structured Query Language)<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">sql<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The result now looks right:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/12\/img_639724be90ec7.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">Products matching a select category.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>The latest command is actually an inner join, even though the word &#8220;join&#8221; is nowhere to be seen. However, I don&#8217;t recommend that syntax; why is that?&nbsp; First, it\u2019s not standard syntax, unlike the syntax you\u2019ll soon see, which is an <a href=\"https:\/\/www.ibm.com\/docs\/en\/informix-servers\/12.10?topic=clause-ansi-joins\" target=\"_blank\" rel=\"noopener\">ANSI standard<\/a>.<\/p>\n\n\n\n<p>The other reason has to do with making your intent clear. The syntax above doesn\u2019t even feature the word \u201cjoin\u201d. Even though it works in performing a join operation, it doesn\u2019t express that fact as explicitly as possible.<\/p>\n\n\n\n<p>The standard syntax for an inner join is as follows:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"SQL (Structured Query Language)\" data-shcb-language-slug=\"sql\"><span><code class=\"hljs language-sql shcb-wrap-lines\"><span class=\"hljs-keyword\">SELECT<\/span> p.description Product, c.description <span class=\"hljs-keyword\">Category<\/span>\n\n<span class=\"hljs-keyword\">FROM<\/span> products p <span class=\"hljs-keyword\">INNER<\/span> <span class=\"hljs-keyword\">JOIN<\/span> categories c <span class=\"hljs-keyword\">ON<\/span> p.category_id = c.id<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">SQL (Structured Query Language)<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">sql<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The outcome you achieve is the same, but in this case, you&#8217;re making it clear that you&#8217;re performing an inner join.&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Inner join when a row fails to match<\/h3>\n\n\n\n<p>As you can see from the example above, the query only retrieves categories that have at least one product belonging to them. The categories &#8220;Toys&#8221; and &#8220;Clothing&#8221; don&#8217;t have any associated products; thus, they don&#8217;t appear.<\/p>\n\n\n\n<p>What would happen if we had a product that didn&#8217;t have a valid category? Let&#8217;s simulate that scenario by deleting one of the categories:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"SQL (Structured Query Language)\" data-shcb-language-slug=\"sql\"><span><code class=\"hljs language-sql shcb-wrap-lines\"><span class=\"hljs-keyword\">delete<\/span> <span class=\"hljs-keyword\">from<\/span> categories <span class=\"hljs-keyword\">where<\/span> <span class=\"hljs-keyword\">id<\/span> = <span class=\"hljs-number\">5<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">SQL (Structured Query Language)<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">sql<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/12\/img_639724bef28d4.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">Updated products after deleting the category of the last item.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>The last product no longer has a category. What will happen now if we perform the inner join again?<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/12\/img_639724bf4315a.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">Updated products after performing an inner join.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>The book by Martin Fowler is no longer listed. I believe the main property of an inner join is now clear: It only brings rows when there is a double match. But what if you wanted to list all products, regardless of whether they have a valid category?<\/p>\n\n\n\n<p>That sounds like a job for the outer join.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Outer joins<\/h3>\n\n\n\n<p>An outer join enables you to list rows even when there are no matches from one or both sides. We&#8217;ll take a look at examples to make things clearer. Continuing with the previous example, let&#8217;s list all of the products regardless of whether they have a category. I&#8217;ll show the command first and then explain it:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"SQL (Structured Query Language)\" data-shcb-language-slug=\"sql\"><span><code class=\"hljs language-sql shcb-wrap-lines\"><span class=\"hljs-keyword\">SELECT<\/span> p.description Product, c.description <span class=\"hljs-keyword\">Category<\/span>\n\n<span class=\"hljs-keyword\">FROM<\/span> products p <span class=\"hljs-keyword\">LEFT<\/span> <span class=\"hljs-keyword\">OUTER<\/span> <span class=\"hljs-keyword\">JOIN<\/span> categories c <span class=\"hljs-keyword\">ON<\/span> p.category_id = c.id<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">SQL (Structured Query Language)<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">sql<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The command above results in all products being listed, even if they have no <code>category_id<\/code>:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/12\/img_639724bf8c773.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">List of all categories present in the database.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>So, that&#8217;s the property of an outer join: It brings all the rows from a given table regardless of whether there&#8217;s a match. In the example above, the priority went to the <code>products<\/code>&nbsp;table: all products were shown regardless of having a valid category. But why?<\/p>\n\n\n\n<p>The answer is that we used the &#8220;left&#8221; variation of the inner join, which privileges the table that comes to the left\u2014that is, first\u2014of the <code>LEFT OUTER JOIN<\/code> clause. The following image makes it very clear:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/12\/img_639724bfd3d90.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">An illustration of the <code>LEFT<\/code> variation of the <code>INNER JOIN<\/code>.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>What if we used the right outer join? In this case, the query privileges the table on the right, displaying all categories\u2014even the ones that don&#8217;t have any products:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/12\/img_639724c0094bc.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">All the categories contained in the database.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>By now, it becomes clear that it would&#8217;ve been possible to achieve the first result\u2014that is, privileging the <code>products<\/code>&nbsp;table\u2014using the right join as well. You&#8217;d have to swap the two tables:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"SQL (Structured Query Language)\" data-shcb-language-slug=\"sql\"><span><code class=\"hljs language-sql shcb-wrap-lines\"><span class=\"hljs-keyword\">SELECT<\/span> p.description Product, c.description <span class=\"hljs-keyword\">Category<\/span>\n\n<span class=\"hljs-keyword\">FROM<\/span> categories c <span class=\"hljs-keyword\">RIGHT<\/span> <span class=\"hljs-keyword\">OUTER<\/span> <span class=\"hljs-keyword\">JOIN<\/span> products p <span class=\"hljs-keyword\">ON<\/span> p.category_id = c.id<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">SQL (Structured Query Language)<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">sql<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>As you&#8217;ve probably noticed, the left and right join operations are analogous: A <code>LEFT OUTER JOIN B<\/code> is the same as <code>B RIGHT OUTER JOIN A<\/code>. Which one should you prefer?<\/p>\n\n\n\n<p>Though there are edge cases in which the right join serves a real purpose, I&#8217;d say that, anecdotally, most people, most of the time, use the left variation. This is also what the MySQL documentation suggests to increase the portability of queries to different databases.<\/p>\n\n\n\n<p>Finally, when using the outer joins, the actual word <code>OUTER<\/code> is optional: You can use <code>LEFT JOIN<\/code> or <code>RIGHT JOIN<\/code>, and the outcome won&#8217;t change.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Full joins<\/h3>\n\n\n\n<p>What if you wanted to list all products and all categories regardless of whether each row has a match? The solution for this scenario is yet another type of outer join called a full outer join. Unfortunately, unlike some other database engines, MySQL doesn&#8217;t support this type of join out of the box.<\/p>\n\n\n\n<p>The alternative is to emulate a full outer join by performing a union between a left and a right join:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"SQL (Structured Query Language)\" data-shcb-language-slug=\"sql\"><span><code class=\"hljs language-sql shcb-wrap-lines\"><span class=\"hljs-keyword\">SELECT<\/span> p.description Product, c.description <span class=\"hljs-keyword\">Category<\/span>\n\n<span class=\"hljs-keyword\">FROM<\/span> products p <span class=\"hljs-keyword\">LEFT<\/span> <span class=\"hljs-keyword\">JOIN<\/span> categories c <span class=\"hljs-keyword\">ON<\/span> p.category_id = c.id\n\n<span class=\"hljs-keyword\">UNION<\/span>\n\n<span class=\"hljs-keyword\">SELECT<\/span> p.description Product, c.description <span class=\"hljs-keyword\">Category<\/span>\n\n<span class=\"hljs-keyword\">FROM<\/span> products p <span class=\"hljs-keyword\">RIGHT<\/span> <span class=\"hljs-keyword\">JOIN<\/span> categories c <span class=\"hljs-keyword\">ON<\/span> p.category_id = c.id<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">SQL (Structured Query Language)<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">sql<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The outcome is now that all rows from both tables are displayed, even when there aren&#8217;t matches:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/12\/img_639724c026a32.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">All rows from the <code>products<\/code> and <code>categories<\/code> tables are displayed.<\/figcaption><\/figure>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\">Cross joins<\/h3>\n\n\n\n<p>A cross join is when you have all rows from one table combined with the other. Here&#8217;s the syntax:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"SQL (Structured Query Language)\" data-shcb-language-slug=\"sql\"><span><code class=\"hljs language-sql shcb-wrap-lines\"><span class=\"hljs-keyword\">SELECT<\/span> * <span class=\"hljs-keyword\">FROM<\/span> products p <span class=\"hljs-keyword\">CROSS<\/span> <span class=\"hljs-keyword\">JOIN<\/span> categories c<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">SQL (Structured Query Language)<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">sql<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This is syntactically equivalent to performing an INNER JOIN without the ON clause:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"SQL (Structured Query Language)\" data-shcb-language-slug=\"sql\"><span><code class=\"hljs language-sql shcb-wrap-lines\"><span class=\"hljs-keyword\">SELECT<\/span> * <span class=\"hljs-keyword\">FROM<\/span> products p <span class=\"hljs-keyword\">INNER<\/span> <span class=\"hljs-keyword\">JOIN<\/span> categories c<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">SQL (Structured Query Language)<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">sql<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>And both are equivalent to the very first example we looked at today:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"SQL (Structured Query Language)\" data-shcb-language-slug=\"sql\"><span><code class=\"hljs language-sql shcb-wrap-lines\"><span class=\"hljs-keyword\">SELECT<\/span> p.description Product, c.description <span class=\"hljs-keyword\">Category<\/span> <span class=\"hljs-keyword\">FROM<\/span> products p, categories c<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">SQL (Structured Query Language)<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">sql<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>All of the three above queries result in 20 rows being displayed, which makes sense if you remember that <code>products<\/code> has five rows and <code>categories<\/code>&nbsp;has four.<\/p>\n\n\n\n<p>In MySQL, <code>JOIN<\/code>, <code>INNER JOIN<\/code>, and <code>CROSS JOIN<\/code> are effectively synonymous, which isn&#8217;t necessarily true when it comes to other database engines.<\/p>\n\n\n<div\n\tclass=\"sandbox-embed responsive-embed  sandbox-embed--full-width\"\n\tstyle=\"padding-top: 85%\"\ndata-block-name=\"coderpad-sandbox-embed\">\n\t<iframe src=\"https:\/\/embed.coderpad.io\/sandbox?question_id=237264&#038;use_question_button\" width=\"640\" height=\"544\" loading=\"lazy\" aria-label=\"Try out the CoderPad sandbox\"><\/iframe>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping up<\/h2>\n\n\n\n<p>Relational databases are all about relationships. That&#8217;s why joins are some of the most crucial operations you can learn. They make it possible to bring data together while enjoying the benefits of database normalization.<\/p>\n\n\n\n<p>Though there are some cases in which joins can affect <a href=\"https:\/\/coderpad.io\/blog\/development\/how-to-use-indexes-to-increase-mysql-database-performance\/\">performance<\/a>, generally speaking, databases are well-equipped to execute them.<\/p>\n\n\n\n<p>Thanks for reading, and until the next time!<\/p>\n\n\n\n<p><em>This post was written by <\/em><em>Carlos Schults. <\/em><a href=\"https:\/\/carlosschults.net\" target=\"_blank\" rel=\"noopener\"><em>Carlos<\/em><\/a><em> is a consultant and software engineer with experience in desktop, web, and mobile development. Though his primary language is C#, he has experience with a number of languages and platforms. His main interests include automated testing, version control, and code quality.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A common need when using a relational database is to combine data from more than one table, creating a cohesive result. In this blog post, we&#8217;ll cover the JOIN clause in MySQL.<\/p>\n","protected":false},"author":1,"featured_media":27299,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[9],"tags":[],"persona":[29],"blog-programming-language":[66],"keyword-cluster":[],"class_list":["post-27127","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development"],"acf":[],"_links":{"self":[{"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/posts\/27127","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/comments?post=27127"}],"version-history":[{"count":58,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/posts\/27127\/revisions"}],"predecessor-version":[{"id":32602,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/posts\/27127\/revisions\/32602"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/media\/27299"}],"wp:attachment":[{"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/media?parent=27127"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/categories?post=27127"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/tags?post=27127"},{"taxonomy":"persona","embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/persona?post=27127"},{"taxonomy":"blog-programming-language","embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/blog-programming-language?post=27127"},{"taxonomy":"keyword-cluster","embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/keyword-cluster?post=27127"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}