eolas/neuron/d0ed26d0-cdc8-4643-8c09-445408195f9b/.neuron/output/Joins_in_SQL.html
2024-10-20 19:00:04 +01:00

80 lines
No EOL
22 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html><html><head><meta content="text/html; charset=utf-8" http-equiv="Content-Type" /><meta content="width=device-width, initial-scale=1" name="viewport" /><!--replace-start-0--><!--replace-start-5--><!--replace-start-8--><title>Joins in SQL - My Zettelkasten</title><!--replace-end-8--><!--replace-end-5--><!--replace-end-0--><link href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.8.7/dist/semantic.min.css" rel="stylesheet" /><link href="https://fonts.googleapis.com/css?family=Merriweather|Libre+Franklin|Roboto+Mono&amp;display=swap" rel="stylesheet" /><!--replace-start-1--><!--replace-start-4--><!--replace-start-7--><link href="https://raw.githubusercontent.com/srid/neuron/master/assets/neuron.svg" rel="icon" /><meta content="We perform joins in SQL when we combine and integrate data from multiple tables. In order for a join to be possible, the tables you want to join must have rows that share the same fields." name="description" /><meta content="Joins in SQL" property="og:title" /><meta content="My Zettelkasten" property="og:site_name" /><meta content="article" property="og:type" /><meta content="Joins_in_SQL" property="neuron:zettel-id" /><meta content="Joins_in_SQL" property="neuron:zettel-slug" /><meta content="SQL" property="neuron:zettel-tag" /><meta content="databases" property="neuron:zettel-tag" /><script type="application/ld+json">[]</script><style type="text/css">body{background-color:#eeeeee !important;font-family:"Libre Franklin", serif !important}body .ui.container{font-family:"Libre Franklin", serif !important}body h1, h2, h3, h4, h5, h6, .ui.header, .headerFont{font-family:"Merriweather", sans-serif !important}body code, pre, tt, .monoFont{font-family:"Roboto Mono","SFMono-Regular","Menlo","Monaco","Consolas","Liberation Mono","Courier New", monospace !important}body div.z-index p.info{color:#808080}body div.z-index ul{list-style-type:square;padding-left:1.5em}body div.z-index .uplinks{margin-left:0.29999em}body .zettel-content h1#title-h1{background-color:rgba(33,133,208,0.1)}body nav.bottomPane{background-color:rgba(33,133,208,2.0e-2)}body div#footnotes{border-top-color:#2185d0}body p{line-height:150%}body img{max-width:100%}body .deemphasized{font-size:0.94999em}body .deemphasized:hover{opacity:1}body .deemphasized:not(:hover){opacity:0.69999}body .deemphasized:not(:hover) a{color:#808080 !important}body div.container.universe{padding-top:1em}body div.zettel-view ul{padding-left:1.5em;list-style-type:square}body div.zettel-view .pandoc .highlight{background-color:#ffff00}body div.zettel-view .pandoc .ui.disabled.fitted.checkbox{margin-right:0.29999em;vertical-align:middle}body div.zettel-view .zettel-content .metadata{margin-top:1em}body div.zettel-view .zettel-content .metadata div.date{text-align:center;color:#808080}body div.zettel-view .zettel-content h1{padding-top:0.2em;padding-bottom:0.2em;text-align:center}body div.zettel-view .zettel-content h2{border-bottom:solid 1px #4682b4;margin-bottom:0.5em}body div.zettel-view .zettel-content h3{margin:0px 0px 0.4em 0px}body div.zettel-view .zettel-content h4{opacity:0.8}body div.zettel-view .zettel-content div#footnotes{margin-top:4em;border-top-style:groove;border-top-width:2px;font-size:0.9em}body div.zettel-view .zettel-content div#footnotes ol > li > p:only-of-type{display:inline;margin-right:0.5em}body div.zettel-view .zettel-content aside.footnote-inline{width:30%;padding-left:15px;margin-left:15px;float:right;background-color:#d3d3d3}body div.zettel-view .zettel-content .overflows{overflow:auto}body div.zettel-view .zettel-content code{margin:auto auto auto auto;font-size:100%}body div.zettel-view .zettel-content p code, li code, ol code{padding:0.2em 0.2em 0.2em 0.2em;background-color:#f5f2f0}body div.zettel-view .zettel-content pre{overflow:auto}body div.zettel-view .zettel-content dl dt{font-weight:bold}body div.zettel-view .zettel-content blockquote{background-color:#f9f9f9;border-left:solid 10px #cccccc;margin:1.5em 0px 1.5em 0px;padding:0.5em 10px 0.5em 10px}body div.zettel-view .zettel-content.raw{background-color:#dddddd}body .ui.label.zettel-tag{color:#000000}body .ui.label.zettel-tag a{color:#000000}body nav.bottomPane ul.backlinks > li{padding-bottom:0.4em;list-style-type:disc}body nav.bottomPane ul.context-list > li{list-style-type:lower-roman}body .footer-version img{-webkit-filter:grayscale(100%);-moz-filter:grayscale(100%);-ms-filter:grayscale(100%);-o-filter:grayscale(100%);filter:grayscale(100%)}body .footer-version img:hover{-webkit-filter:grayscale(0%);-moz-filter:grayscale(0%);-ms-filter:grayscale(0%);-o-filter:grayscale(0%);filter:grayscale(0%)}body .footer-version, .footer-version a, .footer-version a:visited{color:#808080}body .footer-version a{font-weight:bold}body .footer-version{margin-top:1em !important;font-size:0.69999em}@media only screen and (max-width: 768px){body div#zettel-container{margin-left:0.4em !important;margin-right:0.4em !important}}body span.zettel-link-container span.zettel-link a{color:#2185d0;font-weight:bold;text-decoration:none}body span.zettel-link-container span.zettel-link a:hover{background-color:rgba(33,133,208,0.1)}body span.zettel-link-container span.extra{color:auto}body span.zettel-link-container.errors{border:solid 1px #ff0000}body span.zettel-link-container.errors span.zettel-link a:hover{text-decoration:none !important;cursor:not-allowed}body [data-tooltip]:after{font-size:0.69999em}body div.tag-tree div.node{font-weight:bold}body div.tag-tree div.node a.inactive{color:#555555}body .tree.flipped{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}body .tree{overflow:auto}body .tree ul.root{padding-top:0px;margin-top:0px}body .tree ul{position:relative;padding:1em 0px 0px 0px;white-space:nowrap;margin:0px auto 0px auto;text-align:center}body .tree ul::after{content:"";display:table;clear:both}body .tree ul:last-child{padding-bottom:0.1em}body .tree li{display:inline-block;vertical-align:top;text-align:center;list-style-type:none;position:relative;padding:1em 0.5em 0em 0.5em}body .tree li::before{content:"";position:absolute;top:0px;right:50%;border-top:solid 2px #cccccc;width:50%;height:1.19999em}body .tree li::after{content:"";position:absolute;top:0px;right:50%;border-top:solid 2px #cccccc;width:50%;height:1.19999em}body .tree li::after{right:auto;left:50%;border-left:solid 2px #cccccc}body .tree li:only-child{padding-top:0em}body .tree li:only-child::after{display:none}body .tree li:only-child::before{display:none}body .tree li:first-child::before{border-style:none;border-width:0px}body .tree li:first-child::after{border-radius:5px 0px 0px 0px}body .tree li:last-child::after{border-style:none;border-width:0px}body .tree li:last-child::before{border-right:solid 2px #cccccc;border-radius:0px 5px 0px 0px}body .tree ul ul::before{content:"";position:absolute;top:0px;left:50%;border-left:solid 2px #cccccc;width:0px;height:1.19999em}body .tree li div.forest-link{border:solid 2px #cccccc;padding:0.2em 0.29999em 0.2em 0.29999em;text-decoration:none;display:inline-block;border-radius:5px 5px 5px 5px;color:#333333;position:relative;top:2px}body .tree.flipped li div.forest-link{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}</style><script
async=""
id="MathJax-script"
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"
></script>
<link
href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0/themes/prism.min.css"
rel="stylesheet"
/><link rel="preconnect" href="https://fonts.googleapis.com" /><link
rel="preconnect"
href="https://fonts.gstatic.com"
crossorigin
/><link
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=IBM+Plex+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=IBM+Plex+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=IBM+Plex+Serif:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap"
rel="stylesheet"
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0/components/prism-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0/plugins/autoloader/prism-autoloader.min.js"></script>
<style>
body .ui.container,
body ul {
font-family: "IBM Plex Sans" !important;
}
body blockquote {
border-left-width: 3px !important;
font-style: italic;
}
.headerFont,
.ui.header,
body h1,
h2,
h3,
h4,
h5,
h6 {
font-family: "IBM Plex Sans Condensed" !important;
}
body p {
line-height: 1.4;
}
.monoFont,
body code,
pre,
tt {
font-family: "IBM Plex Mono" !important;
font-size: 12px !important;
line-height: 1.4 !important;
}
</style>
<!--replace-end-7--><!--replace-end-4--><!--replace-end-1--></head><body><div class="ui fluid container universe"><!--replace-start-2--><!--replace-start-3--><!--replace-start-6--><div class="ui text container" id="zettel-container" style="position: relative"><div class="zettel-view"><article class="ui raised attached segment zettel-content"><div class="pandoc"><h1 id="title-h1">Joins in SQL</h1><!-- Once a relationship has been created using primary and foreign keys (as detailed in the previous section), you are able to combine and integrate data from the different tables. This is known as performing **joins.** -->
<p>We perform joins in SQL when we combine and integrate data from multiple tables. In order for a join to be possible, <strong>the tables you want to join must have rows that share the same fields</strong>.</p><p>The output will be represented as a table but it is virtual, not an actual table. (If you wish to actually create a table or a view off the back of a join operation you should combine the join with the <span class="zettel-link-container cf"><span class="zettel-link" title="Zettel: Create an SQL table"><a href="Create_an_SQL_table.html"><code>CREATE TABLE</code></a></span></span> command etc.)</p><h2 id="inner-joins">Inner joins</h2><blockquote><p>An inner join combines rows that have matching values in two or more tables. This join is based on the existence of a common field between the tables and is used to retrieve data that appears in both tables.</p></blockquote><p>The following is a good scenario for creating an inner join:</p><blockquote><p>We want to create a list of the name of all computers that have been sold and when they were sold.</p></blockquote><p>We will be working from the following tables.</p><p><em>The <code>sales</code> table</em>:</p><table class="ui table"><thead><tr><th>saleId</th><th>modelId</th><th>saleDate</th><th>employeeId</th><th>price</th></tr></thead><tbody><tr><td>1</td><td>44</td><td>2020-07-27</td><td>tbishop</td><td>40.99</td></tr><tr><td>2</td><td>22</td><td>2021-02-05</td><td>tbishop</td><td>986.99</td></tr><tr><td>3</td><td>14</td><td>2022-11-16</td><td>tgnomay</td><td>1248.99</td></tr></tbody></table><p><em>The <code>model</code> table</em>:</p><table class="ui table"><thead><tr><th>modelId</th><th>modelName</th></tr></thead><tbody><tr><td>44</td><td>Raspberry Pi Model A</td></tr><tr><td>22</td><td>Apple MacBook Air</td></tr><tr><td>14</td><td>Lenovo ThinkPad P15</td></tr></tbody></table><p>The data points we need are not provided in a single table. <code>sales</code> gives us the <code>saleDate</code> but not the <code>modelName</code>. In order to meet our requirements we must perform a join that combines <code>modelName</code> from the <code>model</code> table and <code>saleDate</code> from the <code>sale</code> table to give us a table like the following:</p><table class="ui table"><thead><tr><th>modelName</th><th>sale_date</th></tr></thead><tbody><tr><td>Raspberry Pi Model A</td><td>2015-02-01</td></tr><tr><td>Apple Macbook Air</td><td>2018-11-01</td></tr><tr><td>Lenovo ThinkPad P15</td><td>2018-11-01</td></tr></tbody></table><p>We can do this by utilising the field they have in common: <code>modelId</code>.</p><h3 id="implementation">Implementation</h3><p>The general syntax for creating an inner join from two tables that share a common field is as follows:</p><pre><code class="sql language-sql">SELECT column_name(s)
FROM table1
INNER JOIN table2
ON table1.columnName = table2.columnName</code></pre><p>So basically, look at <code>table1</code> and <code>table2</code> return the rows where the fields for <code>table1</code> and <code>table2</code> match, where these fields are the ones specified in the <code>SELECT</code>.</p><p>Applied to our example:</p><pre><code class="sql language-sql">SELECT model.modelName, sales.saleDate -- Name the fields
FROM model -- Specify the first table
INNER JOIN sales -- Specify the second table
ON model.model_id = sales.model_id; -- Specify the match criteria</code></pre><blockquote><p>It is important to note that the match must <em>be</em> a match. Both tables must have a row with the same value for <code>modelId</code> for the join to be applied. If there is a <code>modelId</code> of X in <code>sales</code> but no corresponding X for <code>modelId</code> in <code>model</code>, nothing will be returned for that row.</p></blockquote><p>We can represent the logical relationship that obtains between the <code>sales</code> and <code>model</code> tables as follows:</p><p><img src="/static/sql-inner-join.png" /></p><h2 id="outer-joins">Outer joins</h2><p>Outer joins are joins that return matched values <strong>and unmatched</strong> values from either or both tables.</p><p>To explain outer joins we need to expand our data set:</p><p><em>The <code>sales</code> table</em>:</p><table class="ui table"><thead><tr><th>saleId</th><th>modelId</th><th>saleDate</th><th>employeeId</th><th>price</th></tr></thead><tbody><tr><td>1</td><td>44</td><td>2020-07-27</td><td>tbishop</td><td>40.99</td></tr><tr><td>2</td><td>22</td><td>2021-02-05</td><td>tbishop</td><td>986.99</td></tr><tr><td>3</td><td>14</td><td>2022-11-16</td><td>tgnomay</td><td>1248.99</td></tr><tr><td>4</td><td></td><td>2020-03-01</td><td>msmelk</td><td>699.99</td></tr></tbody></table><p><em>The <code>model</code> table</em>:</p><table class="ui table"><thead><tr><th>modelId</th><th>modelName</th></tr></thead><tbody><tr><td>44</td><td>Raspberry Pi Model A</td></tr><tr><td>22</td><td>Apple MacBook Air</td></tr><tr><td>14</td><td>Lenovo ThinkPad P15</td></tr><tr><td>66</td><td>Google Chromebook</td></tr></tbody></table><blockquote><p>We will assume that <code>sales</code> is our left table and <code>model</code> our right.</p></blockquote><h3 id="left-outer-join">Left outer join</h3><p>A left outer join returns all records from the left or first table and the matching records from the right or second table. If there are not matches on the right then only the left data is returned.</p><p>In the context of our dataset, in the <em>sales</em> database we have a row where there is a sale with no corresponding <code>modelId</code>. If we performed a left outer join this would give us the following table in return:</p><table class="ui table"><thead><tr><th>modelName</th><th>sale_date</th></tr></thead><tbody><tr><td>Raspberry Pi Model A</td><td>2015-02-01</td></tr><tr><td>Apple Macbook Air</td><td>2018-11-01</td></tr><tr><td>Lenovo ThinkPad P15</td><td>2018-11-01</td></tr><tr><td></td><td>2020-03-01</td></tr></tbody></table><p>The logical relationship sustained between <code>sales</code> and <code>model</code> by a left inner join is represented in the following diagram:</p><p><img src="/static/sql-left-outer-join.png" /></p><h4 id="implementation-1">Implementation</h4><p>The schematic form:</p><pre><code class="sql language-sql">SELECT column_name(s)
FROM table1
LEFT JOIN table2
ON table1.column_name = table2.column_name;</code></pre><p>Applied to our data set:</p><pre><code class="sql language-sql">SELECT model.modelName, sales.saleDate
FROM sales.saleDate
LEFT JOIN model
ON sales.modelId = model.modelId</code></pre><h3 id="right-outer-join">Right outer join</h3><p>This is the inverse of the right outer join. A right outer join returns all records from the right or second table and the matching records from the left or first table. If there are not matches on the left then only the right data is returned.</p><p>In the context of our dataset, in the <em>model</em> database we have a row where there is a <code>modelId</code> without a corresponding entry in the <code>sales</code> table. If we performed a right outer join this would give us the following table in return:</p><table class="ui table"><thead><tr><th>modelName</th><th>sale_date</th></tr></thead><tbody><tr><td>Raspberry Pi Model A</td><td>2015-02-01</td></tr><tr><td>Apple Macbook Air</td><td>2018-11-01</td></tr><tr><td>Lenovo ThinkPad P15</td><td>2018-11-01</td></tr><tr><td>Google Chromebook</td><td></td></tr></tbody></table><p>The logical relationship sustained between <code>sales</code> and <code>model</code> by a right inner join is represented in the following diagram:</p><p><img src="/static/sql-right-outer-join.png" /></p><h4 id="implementation-2">Implementation</h4><p>The schematic form:</p><pre><code class="sql language-sql">SELECT column_name(s)
FROM table1
RIGHT JOIN table2
ON table1.column_name = table2.column_name;</code></pre><p>Applied to our data set:</p><pre><code class="sql language-sql">SELECT model.modelName, sales.saleDate
FROM sales.saleDate
RIGHT JOIN model
ON sales.modelId = model.modelId</code></pre><h3 id="full-outer-join">Full outer join</h3><p>The full outer join returns all rows when there is a match in either the left or the right table. So, for table A and table B the full join returns all rows in A and all rows in B including those where there is a match between A and B. This is the broadest type of join and can often result in large data sets.</p><p>In the context of our dataset it would result in the following table being generated:</p><table class="ui table"><thead><tr><th>modelName</th><th>sale_date</th></tr></thead><tbody><tr><td>Raspberry Pi Model A</td><td>2015-02-01</td></tr><tr><td>Apple Macbook Air</td><td>2018-11-01</td></tr><tr><td>Lenovo ThinkPad P15</td><td>2018-11-01</td></tr><tr><td></td><td>2020-03-01</td></tr><tr><td>Google Chromebook</td><td></td></tr></tbody></table><p>Represented by the following diagram:</p><p><img src="/static/sql-full-outer-join.png" /></p><h4 id="implementation-3">Implementation</h4><p>The schematic form:</p><pre><code class="sql language-sql">SELECT column_name(s)
FROM table1
FULL OUTER JOIN table2
ON table1.column_name = table2.column_name;</code></pre><p>Applied to our data set:</p><pre><code class="sql language-sql">SELECT model.modelName, sales.saleDate
FROM sales.saleDate
FULL OUTER JOIN model
ON sales.modelId = model.modelId</code></pre><p>This type of join is used when you want to discern when there is <em>not</em> a match between two fields across tables. For example: imagine that you wanted a list of computers that had never been sold. In this case, you would be interested in rows where there is a <code>model_id</code> without a corresponding <code>sales_id</code> .</p><p>In SQL this would be achieved with:</p><pre><code class="sql language-sql">SELECT model.name, sales.sale_date
FROM model
LEFT JOIN sales on model.model_id = sales.model_id;</code></pre><p>Note that this would return all the model names but where there isnt a sale data, <code>NULL</code> would be returned. This is an <strong>important distinction :</strong> the outer join method doesnt just return the rows with a <code>NULL</code> value for <code>sale_date</code> as we might expect. It returns all models along with those that have not been sold. This is because it is oriented to the “left” table, equivalent to the table in the SQL that we cited first with the <code>on</code> keyword.</p><blockquote><p>A left outer join returns all the records from the left (model) table and those that match in the right (sales) table. Where there are no matching records in the right (sales) table, a <code>NULL</code> value is returned.</p></blockquote><p>A <strong>right outer join</strong>, often referred to as a right join, is the opposite of a left outer; it returns all the records from the right table and those that match in the left table. In our scenario this would be all the models that had a <code>sale_date</code> including models that didnt have a <code>sale_date</code> , i.e which returned <code>NULL</code></p><p>Finally, a <strong>full outer join</strong> returns all the records from both tables, and where a record cannot be matched, a NULL value is returned. So this would mean there could be <code>NULL</code>s in both fields of the returned rows.</p><p>We can combine multiple types of join in the same SQL query:</p><pre><code class="sql language-sql">SELECT model.name, sales.sale_date, manufacturer.url
FROM model
LEFT JOIN sales on model.model_id = sales.model_id
INNER JOIN manufacturer on model.manufacturer_id = manufacturer.manufacturer_id;</code></pre></div></article><nav class="ui attached segment deemphasized bottomPane" id="neuron-tags-pane"><div><span class="ui basic label zettel-tag" title="Tag">SQL</span><span class="ui basic label zettel-tag" title="Tag">databases</span></div></nav><nav class="ui bottom attached icon compact inverted menu blue" id="neuron-nav-bar"><!--replace-start-9--><!--replace-end-9--><a class="right item" href="impulse.html" title="Open Impulse"><i class="wave square icon"></i></a></nav></div></div><!--replace-end-6--><!--replace-end-3--><!--replace-end-2--><div class="ui center aligned container footer-version"><div class="ui tiny image"><a href="https://neuron.zettel.page"><img alt="logo" src="https://raw.githubusercontent.com/srid/neuron/master/assets/neuron.svg" title="Generated by Neuron 1.9.35.3" /></a></div></div></div></body></html>