<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Faith Njenga</title>
    <description>The latest articles on DEV Community by Faith Njenga (@ms_njenga).</description>
    <link>https://dev.to/ms_njenga</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3952258%2Fcdee308c-1da8-4d47-b865-37630a414717.jpeg</url>
      <title>DEV Community: Faith Njenga</title>
      <link>https://dev.to/ms_njenga</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ms_njenga"/>
    <language>en</language>
    <item>
      <title>SQL Is Surviving, Franklin: When Tables Start Talking</title>
      <dc:creator>Faith Njenga</dc:creator>
      <pubDate>Tue, 08 Sep 2026 13:09:53 +0000</pubDate>
      <link>https://dev.to/ms_njenga/sql-is-surviving-franklin-when-tables-start-talking-3oom</link>
      <guid>https://dev.to/ms_njenga/sql-is-surviving-franklin-when-tables-start-talking-3oom</guid>
      <description>&lt;p&gt;So, you survived the basics of SQL.&lt;/p&gt;

&lt;p&gt;You learned how to create tables, insert data, retrieve records, update rows, and hopefully avoid accidentally updating the entire database.&lt;/p&gt;

&lt;p&gt;Because if you’ve ever run a &lt;code&gt;DELETE&lt;/code&gt; statement without a &lt;code&gt;WHERE&lt;/code&gt; clause and survived the experience, congratulations. You’ve already developed character.&lt;/p&gt;

&lt;p&gt;But eventually, SQL gives you another problem: &lt;strong&gt;“Cool. Now get information from multiple tables.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And suddenly, &lt;code&gt;SELECT * FROM students;&lt;/code&gt; doesn’t feel so powerful anymore.&lt;/p&gt;

&lt;p&gt;Welcome to JOINs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Previously in SQL…
&lt;/h2&gt;

&lt;p&gt;In Part 1, we looked at the basic categories of SQL commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DDL&lt;/strong&gt; - Data Definition Language&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DML&lt;/strong&gt; - Data Manipulation Language&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DQL&lt;/strong&gt; - Data Query Language&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also worked with individual tables. But real databases rarely keep everything in one giant table.&lt;/p&gt;

&lt;p&gt;Imagine trying to store an entire school database in one table:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;student_name&lt;/th&gt;
&lt;th&gt;class&lt;/th&gt;
&lt;th&gt;teacher&lt;/th&gt;
&lt;th&gt;subject&lt;/th&gt;
&lt;th&gt;score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Brian&lt;/td&gt;
&lt;td&gt;Form 4A&lt;/td&gt;
&lt;td&gt;Mr. Kamau&lt;/td&gt;
&lt;td&gt;Mathematics&lt;/td&gt;
&lt;td&gt;78&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mercy&lt;/td&gt;
&lt;td&gt;Form 4A&lt;/td&gt;
&lt;td&gt;Mr. Kamau&lt;/td&gt;
&lt;td&gt;Mathematics&lt;/td&gt;
&lt;td&gt;91&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kevin&lt;/td&gt;
&lt;td&gt;Form 3B&lt;/td&gt;
&lt;td&gt;Ms. Achieng&lt;/td&gt;
&lt;td&gt;Biology&lt;/td&gt;
&lt;td&gt;84&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At first, this looks convenient. Until you realize that you’re repeating class, teacher, subject, and student information over and over again.&lt;/p&gt;

&lt;p&gt;That’s where relational databases come in.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Do We Have Multiple Tables?
&lt;/h2&gt;

&lt;p&gt;A good database tries to avoid unnecessary repetition. Instead of putting everything into one massive table, we separate related information.&lt;/p&gt;

&lt;p&gt;Let’s say our school is called &lt;strong&gt;Greenwood Academy&lt;/strong&gt;. We could split our data into three clean tables:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;students&lt;/code&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;student_id&lt;/th&gt;
&lt;th&gt;student_name&lt;/th&gt;
&lt;th&gt;class_id&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Brian&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Mercy&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Kevin&lt;/td&gt;
&lt;td&gt;102&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;classes&lt;/code&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;class_id&lt;/th&gt;
&lt;th&gt;class_name&lt;/th&gt;
&lt;th&gt;teacher_id&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;Form 4A&lt;/td&gt;
&lt;td&gt;501&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;102&lt;/td&gt;
&lt;td&gt;Form 3B&lt;/td&gt;
&lt;td&gt;502&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;teachers&lt;/code&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;teacher_id&lt;/th&gt;
&lt;th&gt;teacher_name&lt;/th&gt;
&lt;th&gt;subject&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;501&lt;/td&gt;
&lt;td&gt;Mr. Kamau&lt;/td&gt;
&lt;td&gt;Mathematics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;502&lt;/td&gt;
&lt;td&gt;Ms. Achieng&lt;/td&gt;
&lt;td&gt;Biology&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now the information is nicely separated. But there’s a problem. If someone asks: &lt;em&gt;“Show me each student’s name, their class, and their teacher.”&lt;/em&gt; - no single table contains all three pieces of information.&lt;/p&gt;

&lt;p&gt;So how do we bring them together? You guessed it. &lt;strong&gt;JOINs&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Before JOINs: Primary Keys and Foreign Keys
&lt;/h2&gt;

&lt;p&gt;Before we start joining tables like we’re collecting Pokémon, we need to understand what connects them. That connection usually comes from &lt;strong&gt;primary keys&lt;/strong&gt; and &lt;strong&gt;foreign keys&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Primary Key
&lt;/h3&gt;

&lt;p&gt;A primary key uniquely identifies each record in a table. For example, &lt;code&gt;student_id&lt;/code&gt; might uniquely identify every student. No two students should ever share the same &lt;code&gt;student_id&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Foreign Key
&lt;/h3&gt;

&lt;p&gt;A foreign key is a column that refers to a primary key in another table. &lt;/p&gt;

&lt;p&gt;For example, look at the relationship between our &lt;code&gt;students&lt;/code&gt; and &lt;code&gt;classes&lt;/code&gt; tables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;students                 classes
-----------              -----------
student_id               class_id  &amp;lt;--- (Primary Key)
student_name                ↑
class_id    ────────────────┘ 
   │
   └─&amp;gt; (Foreign Key)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s the exact relationship SQL uses to connect the tables. Think of it as the database saying: &lt;em&gt;“I don’t have the whole story here, but I know exactly where the rest of it lives.”&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  So… What Exactly Is a JOIN?
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;JOIN&lt;/code&gt; allows you to combine rows from two or more tables based on a related column.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;student_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we’re saying: &lt;em&gt;“Take the students table, find the class that belongs to each student, and bring the information together side-by-side.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The magic happens right here: &lt;code&gt;ON students.class_id = classes.class_id&lt;/code&gt;. That is the structural bridge we are using to link them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Meet the JOIN Family
&lt;/h2&gt;

&lt;p&gt;SQL has several types of JOINs. The main ones you’ll encounter are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;INNER JOIN&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LEFT JOIN&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RIGHT JOIN&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FULL OUTER JOIN&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s break down how they behave differently.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. INNER JOIN
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;INNER JOIN&lt;/code&gt; returns only the records that have a match in &lt;strong&gt;both&lt;/strong&gt; tables. Think of it as: &lt;em&gt;“Only show me people who are actually on both guest lists.”&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;student_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Imagine our dataset looks like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Students Table:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;student_id&lt;/th&gt;
&lt;th&gt;student_name&lt;/th&gt;
&lt;th&gt;class_id&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Brian&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Mercy&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Kevin&lt;/td&gt;
&lt;td&gt;102&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Sarah&lt;/td&gt;
&lt;td&gt;999&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Classes Table:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;class_id&lt;/th&gt;
&lt;th&gt;class_name&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;Form 4A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;102&lt;/td&gt;
&lt;td&gt;Form 3B&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sarah’s &lt;code&gt;class_id&lt;/code&gt; is &lt;code&gt;999&lt;/code&gt;. Since there is no class with a &lt;code&gt;class_id&lt;/code&gt; of &lt;code&gt;999&lt;/code&gt; in the classes table, Sarah disappears from the results entirely. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;INNER JOIN&lt;/code&gt; basically says: &lt;em&gt;“If we can’t find a perfect match, drop the row.”&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  2. LEFT JOIN
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;LEFT JOIN&lt;/code&gt; returns &lt;strong&gt;all records from the left table&lt;/strong&gt;, and the matching records from the right table. If there is no match, SQL fills the right-side columns with &lt;code&gt;NULL&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;student_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the same data from before, Sarah would now appear in our results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;student_name&lt;/th&gt;
&lt;th&gt;class_name&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Brian&lt;/td&gt;
&lt;td&gt;Form 4A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mercy&lt;/td&gt;
&lt;td&gt;Form 4A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kevin&lt;/td&gt;
&lt;td&gt;Form 3B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sarah&lt;/td&gt;
&lt;td&gt;NULL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Because the &lt;code&gt;students&lt;/code&gt; table is written first (on the left side of the JOIN keyword), the &lt;code&gt;LEFT JOIN&lt;/code&gt; mandates: &lt;em&gt;“I don’t care if you find a match or not. Everybody from my table is coming along.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is incredibly useful when you want to look for missing or unlinked records. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;student_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are specifically filtering for students who don’t have a matching class. SQL has officially entered detective mode.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. RIGHT JOIN
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;RIGHT JOIN&lt;/code&gt; is the exact opposite of &lt;code&gt;LEFT JOIN&lt;/code&gt;. It keeps all records from the right table, even if there isn’t a matching record in the left table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;student_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;RIGHT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This states: &lt;em&gt;“Every class stays. If a student belongs to it, bring them along. If a class has zero students, display the class name anyway and fill the student column with &lt;code&gt;NULL&lt;/code&gt;.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That said, &lt;code&gt;RIGHT JOIN&lt;/code&gt; isn’t used as often in the real world. Why? Because you can always rewrite it as a &lt;code&gt;LEFT JOIN&lt;/code&gt; simply by flipping the order of your tables in the query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;student_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same idea, different direction. Keeping everything as a &lt;code&gt;LEFT JOIN&lt;/code&gt; usually makes scripts much easier to read from top to bottom.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. FULL OUTER JOIN
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;FULL OUTER JOIN&lt;/code&gt; goes completely all-in. It keeps matching records, unmatched records from the left table, &lt;strong&gt;and&lt;/strong&gt; unmatched records from the right table.&lt;/p&gt;

&lt;p&gt;Essentially: &lt;em&gt;“Bring everybody to the party. We’ll figure out the missing pieces later.”&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;student_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;FULL&lt;/span&gt; &lt;span class="k"&gt;OUTER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This query will simultaneously surface:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Students assigned to classes.&lt;/li&gt;
&lt;li&gt;Students without classes (like Sarah).&lt;/li&gt;
&lt;li&gt;Dynamic classes that currently have no students assigned to them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Important Note:&lt;/strong&gt; Not every database system supports &lt;code&gt;FULL OUTER JOIN&lt;/code&gt; directly out of the box. For example, MySQL does not support it natively (you have to fake it using a &lt;code&gt;UNION&lt;/code&gt; of a Left and Right Join), whereas engines like PostgreSQL do. Always verify which database system you're building for.&lt;/p&gt;




&lt;h2&gt;
  
  
  JOIN Cheat Sheet
&lt;/h2&gt;

&lt;p&gt;If you forget everything else, keep this quick mental framework handy:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;JOIN Type&lt;/th&gt;
&lt;th&gt;What does it keep?&lt;/th&gt;
&lt;th&gt;Quick Analogy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;INNER JOIN&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only matching records&lt;/td&gt;
&lt;td&gt;The intersection only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;LEFT JOIN&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Everything from the left table + matches&lt;/td&gt;
&lt;td&gt;Left table gets full VIP treatment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;RIGHT JOIN&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Everything from the right table + matches&lt;/td&gt;
&lt;td&gt;Right table gets full VIP treatment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;FULL OUTER JOIN&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Everything from both tables&lt;/td&gt;
&lt;td&gt;Universal invite list&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  The ON Clause: Where the Magic Happens
&lt;/h2&gt;

&lt;p&gt;You’ve probably noticed this piece of syntax repeating: &lt;code&gt;ON students.class_id = classes.class_id&lt;/code&gt;.&lt;br&gt;
The &lt;code&gt;ON&lt;/code&gt; clause tells SQL exactly how the tables are related.&lt;/p&gt;


&lt;h2&gt;
  
  
  JOINing Three Tables
&lt;/h2&gt;

&lt;p&gt;What if we want to bridge all three of our tables together to find out which &lt;strong&gt;teacher&lt;/strong&gt; is teaching which &lt;strong&gt;student&lt;/strong&gt;? &lt;/p&gt;

&lt;p&gt;You aren't limited to joining just two tables at a time. You can chain JOIN statements sequentially to build broader horizons. SQL will process them linearly, using the cumulative dataset from the first join to connect to the next table.&lt;/p&gt;

&lt;p&gt;Here is how you link &lt;code&gt;students&lt;/code&gt; to &lt;code&gt;classes&lt;/code&gt;, and then connect those &lt;code&gt;classes&lt;/code&gt; to their respective &lt;code&gt;teachers&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; 
&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;student_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;teacher_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt; &lt;span class="n"&gt;sINNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt; &lt;span class="n"&gt;cON&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_idINNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;teachers&lt;/span&gt; &lt;span class="n"&gt;tON&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;teacher_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;teacher_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pro-Tip: Table Aliasing
&lt;/h3&gt;

&lt;p&gt;Notice the letters s, c, and t right after the table names? Those are aliases. They save you from having to type out long table names like students. student_name repeatedly. By declaring FROM students s, you tell SQL: "For the rest of this query, I'll just use s as a shorthand for this table." It keeps your multi-table joins beautifully organized and readable!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>database</category>
      <category>sql</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Surviving SQL Is Winning, Franklin</title>
      <dc:creator>Faith Njenga</dc:creator>
      <pubDate>Mon, 27 Jul 2026 08:28:43 +0000</pubDate>
      <link>https://dev.to/ms_njenga/surviving-sql-is-winning-franklin-25kn</link>
      <guid>https://dev.to/ms_njenga/surviving-sql-is-winning-franklin-25kn</guid>
      <description>&lt;p&gt;I was given a PostgreSQL assignment.&lt;/p&gt;

&lt;p&gt;The brief said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are now the DBA for Greenwood Academy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No handover meeting. No existing documentation. No senior DBA saying, “Here is what happened last quarter.”&lt;/p&gt;

&lt;p&gt;Just a school, some messy data, and a list of tasks.&lt;/p&gt;

&lt;p&gt;So I opened &lt;strong&gt;DBeaver&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For anyone new to this: I was using DBeaver to connect to &lt;strong&gt;PostgreSQL&lt;/strong&gt; and run my SQL queries. PostgreSQL is the database system. DBeaver is the tool I used to work with it.&lt;/p&gt;

&lt;p&gt;I wrote the instructions in DBeaver.&lt;/p&gt;

&lt;p&gt;PostgreSQL did the actual work.&lt;/p&gt;

&lt;p&gt;And, as I would soon discover, PostgreSQL was very committed to doing exactly what I told it to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  SQL Has Departments
&lt;/h2&gt;

&lt;p&gt;Before touching Greenwood Academy, I needed to understand the different types of SQL commands.&lt;/p&gt;

&lt;p&gt;SQL commands are grouped according to what they do. Think of them as different departments in the same organisation. They all work with the database, but they have different jobs.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Full Name&lt;/th&gt;
&lt;th&gt;Main Job&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DDL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data Definition Language&lt;/td&gt;
&lt;td&gt;Creates and changes database structures&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;CREATE&lt;/code&gt;, &lt;code&gt;ALTER&lt;/code&gt;, &lt;code&gt;DROP&lt;/code&gt;, &lt;code&gt;TRUNCATE&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DML&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data Manipulation Language&lt;/td&gt;
&lt;td&gt;Adds, changes, and removes data&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DQL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data Query Language&lt;/td&gt;
&lt;td&gt;Retrieves data&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SELECT&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DCL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data Control Language&lt;/td&gt;
&lt;td&gt;Manages permissions and access&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;GRANT&lt;/code&gt;, &lt;code&gt;REVOKE&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TCL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Transaction Control Language&lt;/td&gt;
&lt;td&gt;Manages database transactions&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;COMMIT&lt;/code&gt;, &lt;code&gt;ROLLBACK&lt;/code&gt;, &lt;code&gt;SAVEPOINT&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The quick version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DDL → Build the structure
DML → Change the data
DQL → Ask questions
DCL → Control access
TCL → Decide whether changes stay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will not use every command in this article. Greenwood Academy did not require me to manage database permissions or recover from a transaction disaster.&lt;/p&gt;

&lt;p&gt;This assignment focused mainly on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DDL → CREATE, ALTER
DML → INSERT, UPDATE, DELETE
DQL → SELECT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will also use &lt;code&gt;WHERE&lt;/code&gt;, &lt;code&gt;AND&lt;/code&gt;, &lt;code&gt;OR&lt;/code&gt;, &lt;code&gt;BETWEEN&lt;/code&gt;, &lt;code&gt;IN&lt;/code&gt;, &lt;code&gt;NOT IN&lt;/code&gt;, &lt;code&gt;LIKE&lt;/code&gt;, &lt;code&gt;COUNT(*)&lt;/code&gt;, and &lt;code&gt;CASE WHEN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, with the departments introduced, it was time to start with the construction department.&lt;/p&gt;

&lt;h2&gt;
  
  
  SECTION A: DDL - Building Greenwood Academy
&lt;/h2&gt;

&lt;p&gt;DDL stands for &lt;strong&gt;Data Definition Language&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;DDL is about the structure of the database.&lt;/p&gt;

&lt;p&gt;Before asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which students are in Form 3?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;we need somewhere to store the students.&lt;/p&gt;

&lt;p&gt;Before storing exam results, we need somewhere to put the results.&lt;/p&gt;

&lt;p&gt;So the first task was to create a schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;SCHEMA&lt;/span&gt; &lt;span class="n"&gt;greenwood_academy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A schema helps organise database objects. I wanted the Greenwood Academy tables grouped together instead of scattered around the database like files named:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final.sql
final2.sql
final_final.sql
final_final_use_this_one.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I set the schema as the working location:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;search_path&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;greenwood_academy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now PostgreSQL knew where I wanted to work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Tables
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;students&lt;/code&gt; table needed a unique ID, names, gender, date of birth, class, and city:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;student_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;first_name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;last_name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;gender&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;date_of_birth&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;student_id&lt;/code&gt; is the &lt;code&gt;PRIMARY KEY&lt;/code&gt;, meaning each student must have a unique identifier.&lt;/p&gt;

&lt;p&gt;Because names are not always enough.&lt;/p&gt;

&lt;p&gt;You can have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Brian Ochieng
Brian Ochieng
Brian Ochieng
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But their IDs should still be different.&lt;/p&gt;

&lt;p&gt;The database does not care which Brian sits near the window. The database wants the ID.&lt;/p&gt;

&lt;p&gt;Next came the subjects table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;subjects&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;subject_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;subject_name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;department&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;teacher_name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;credits&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;UNIQUE&lt;/code&gt; constraint on &lt;code&gt;subject_name&lt;/code&gt; helps prevent duplicate subject names.&lt;/p&gt;

&lt;p&gt;Because we probably do not need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mathematics
Mathematics
Mathematics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;unless Mathematics has somehow become three different departments.&lt;/p&gt;

&lt;p&gt;Finally, the exam results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;exam_results&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;result_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;student_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;subject_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;marks&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;exam_date&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;grade&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of repeatedly storing the student's full name and every other detail in every exam record, we use IDs.&lt;/p&gt;

&lt;p&gt;That keeps the data more organised and saves us from trying to determine whether these are four different people:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Amina Wanjiku
Amina Wanjiku 
AMINA WANJIKU
Amina Wanjiku N.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sometimes the database problem is not the database.&lt;/p&gt;

&lt;p&gt;Sometimes it is the person who entered the data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Then the Requirements Changed
&lt;/h3&gt;

&lt;p&gt;Once the tables were created, someone realised the students table needed a phone number.&lt;/p&gt;

&lt;p&gt;So we added one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;phone_number&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the &lt;code&gt;credits&lt;/code&gt; column needed a new name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;subjects&lt;/span&gt;
&lt;span class="k"&gt;RENAME&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;credits&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;credit_hours&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the phone number was no longer needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;phone_number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Added.&lt;/p&gt;

&lt;p&gt;Renamed.&lt;/p&gt;

&lt;p&gt;Removed.&lt;/p&gt;

&lt;p&gt;The database had barely settled down.&lt;/p&gt;

&lt;p&gt;This is a realistic introduction to working with requirements. Someone says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“We need this column.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You add it.&lt;/p&gt;

&lt;p&gt;Then:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Actually, we don't need it.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You remove it.&lt;/p&gt;

&lt;p&gt;Then, three months later:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Why doesn't the column exist anymore?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is why database work requires technical skills and the ability to remain calm while requirements perform a complete Nairobi matatu route change.&lt;/p&gt;

&lt;h2&gt;
  
  
  SECTION B: DML - Putting Data Into the Tables
&lt;/h2&gt;

&lt;p&gt;DDL built the structure.&lt;/p&gt;

&lt;p&gt;Now we needed data.&lt;/p&gt;

&lt;p&gt;DML stands for &lt;strong&gt;Data Manipulation Language&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The main commands are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSERT
UPDATE
DELETE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where the database starts becoming useful.&lt;/p&gt;

&lt;p&gt;It is also where you start reading your queries twice.&lt;/p&gt;

&lt;p&gt;Maybe three times.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;INSERT&lt;/code&gt;: Adding the Data
&lt;/h2&gt;

&lt;p&gt;The first student:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;date_of_birth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Amina'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Wanjiku'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'F'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2008-03-12'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Form 3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Nairobi'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the remaining students were inserted.&lt;/p&gt;

&lt;p&gt;The data included students from Nairobi, Mombasa, Kisumu, Nakuru, and Eldoret.&lt;/p&gt;

&lt;p&gt;Then came the subjects.&lt;/p&gt;

&lt;p&gt;Then the exam results.&lt;/p&gt;

&lt;p&gt;At this point, the database had data.&lt;/p&gt;

&lt;p&gt;Which meant it was time for the data to be wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Esther Moved From Nakuru to Nairobi
&lt;/h2&gt;

&lt;p&gt;Esther Akinyi had moved from Nakuru to Nairobi.&lt;/p&gt;

&lt;p&gt;The database still had her old city.&lt;/p&gt;

&lt;p&gt;So:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Nairobi'&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;student_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;WHERE&lt;/code&gt; clause tells PostgreSQL exactly which student to update.&lt;/p&gt;

&lt;p&gt;Student number 5.&lt;/p&gt;

&lt;p&gt;Esther.&lt;/p&gt;

&lt;p&gt;Not everyone.&lt;/p&gt;

&lt;p&gt;Now look at this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Nairobi'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That updates every student.&lt;/p&gt;

&lt;p&gt;Amina moves to Nairobi.&lt;/p&gt;

&lt;p&gt;Brian moves to Nairobi.&lt;/p&gt;

&lt;p&gt;Cynthia moves to Nairobi.&lt;/p&gt;

&lt;p&gt;Everyone moves to Nairobi.&lt;/p&gt;

&lt;p&gt;Mombasa is finished.&lt;/p&gt;

&lt;p&gt;Nakuru is finished.&lt;/p&gt;

&lt;p&gt;Eldoret is now a historical concept.&lt;/p&gt;

&lt;p&gt;This is why a missing &lt;code&gt;WHERE&lt;/code&gt; clause can ruin your career.&lt;/p&gt;

&lt;p&gt;The database does not stop and ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Are you sure you meant all 10 students?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It does exactly what you wrote.&lt;/p&gt;

&lt;p&gt;Which is admirable.&lt;/p&gt;

&lt;p&gt;Until you realise what you wrote.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 49 That Was Actually a 59
&lt;/h2&gt;

&lt;p&gt;Result number 5 had the wrong mark.&lt;/p&gt;

&lt;p&gt;The database said &lt;code&gt;49&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The correct mark was &lt;code&gt;59&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;exam_results&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;marks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;59&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;result_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One record.&lt;/p&gt;

&lt;p&gt;One correction.&lt;/p&gt;

&lt;p&gt;Done.&lt;/p&gt;

&lt;p&gt;Now imagine this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;exam_results&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;marks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every exam result is now 59.&lt;/p&gt;

&lt;p&gt;The student who scored 95?&lt;/p&gt;

&lt;p&gt;59.&lt;/p&gt;

&lt;p&gt;The student who scored 78?&lt;/p&gt;

&lt;p&gt;59.&lt;/p&gt;

&lt;p&gt;The student who scored 49?&lt;/p&gt;

&lt;p&gt;Also 59.&lt;/p&gt;

&lt;p&gt;We have not corrected the data.&lt;/p&gt;

&lt;p&gt;We have created a very strange grading policy.&lt;/p&gt;

&lt;p&gt;This is the moment you start appreciating the humble &lt;code&gt;WHERE&lt;/code&gt; clause.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Canceled Exam
&lt;/h2&gt;

&lt;p&gt;Result number 9 had been canceled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;exam_results&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;result_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One result removed.&lt;/p&gt;

&lt;p&gt;The dangerous version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;exam_results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That deletes every exam result.&lt;/p&gt;

&lt;p&gt;No warning.&lt;/p&gt;

&lt;p&gt;No popup.&lt;/p&gt;

&lt;p&gt;No person from IT appearing beside you asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“What exactly are you doing?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The database trusts you.&lt;/p&gt;

&lt;p&gt;Perhaps too literally.&lt;/p&gt;

&lt;p&gt;A good habit is to check the row before changing or deleting it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;exam_results&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;result_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the correct row appears, then delete it.&lt;/p&gt;

&lt;p&gt;The same principle applies to updates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;student_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Nairobi'&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;student_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, inspect.&lt;/p&gt;

&lt;p&gt;Then, change.&lt;/p&gt;

&lt;p&gt;Because fixing one student's city is a normal database task.&lt;/p&gt;

&lt;p&gt;Explaining why the entire school now lives in Nairobi is a different kind of meeting.&lt;/p&gt;

&lt;h2&gt;
  
  
  SECTION C: DQL - Asking the Database Questions
&lt;/h2&gt;

&lt;p&gt;Now we get to &lt;code&gt;SELECT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;DQL stands for &lt;strong&gt;Data Query Language&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The database has the data.&lt;/p&gt;

&lt;p&gt;We ask questions.&lt;/p&gt;

&lt;p&gt;To find Form 4 students:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Form 4'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To find subjects in the Sciences department:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;subjects&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;department&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Sciences'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To find exam results with marks of 70 or above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;exam_results&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;marks&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To find female students:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;gender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'F'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the basic idea behind &lt;code&gt;WHERE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You describe what you want.&lt;/p&gt;

&lt;p&gt;The database checks the rows.&lt;/p&gt;

&lt;p&gt;It returns what matches.&lt;/p&gt;

&lt;p&gt;No manually scanning through hundreds of spreadsheet rows and hoping you did not accidentally leave a filter active from yesterday.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;AND&lt;/code&gt;: When Both Conditions Must Be True
&lt;/h2&gt;

&lt;p&gt;The assignment asked us to find students who were in Form 3 &lt;strong&gt;and&lt;/strong&gt; from Nairobi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Form 3'&lt;/span&gt;
&lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Nairobi'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both conditions must be true.&lt;/p&gt;

&lt;p&gt;A Form 3 student from Kisumu does not qualify.&lt;/p&gt;

&lt;p&gt;A Nairobi student in Form 4 does not qualify.&lt;/p&gt;

&lt;p&gt;You can add more conditions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;gender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'F'&lt;/span&gt;
&lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Form 3'&lt;/span&gt;
&lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Nairobi'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now all three conditions must be true.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;OR&lt;/code&gt;: When Either Condition Works
&lt;/h2&gt;

&lt;p&gt;Now we want students in Form 2 or Form 4:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Form 2'&lt;/span&gt;
&lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Form 4'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Form 2?&lt;/p&gt;

&lt;p&gt;Include.&lt;/p&gt;

&lt;p&gt;Form 4?&lt;/p&gt;

&lt;p&gt;Include.&lt;/p&gt;

&lt;p&gt;Form 3?&lt;/p&gt;

&lt;p&gt;Not this time.&lt;/p&gt;

&lt;p&gt;The difference is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AND → all conditions must be true
OR  → at least one condition must be true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two small words.&lt;/p&gt;

&lt;p&gt;Very different results.&lt;/p&gt;

&lt;h2&gt;
  
  
  SECTION D: Better Ways to Filter Data
&lt;/h2&gt;

&lt;p&gt;Sometimes the question is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is this value exactly equal to that value?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes we need a range, a list, or a pattern.&lt;/p&gt;

&lt;p&gt;That is where &lt;code&gt;BETWEEN&lt;/code&gt;, &lt;code&gt;IN&lt;/code&gt;, &lt;code&gt;NOT IN&lt;/code&gt;, and &lt;code&gt;LIKE&lt;/code&gt; become useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;BETWEEN&lt;/code&gt;: Working With a Range
&lt;/h2&gt;

&lt;p&gt;To find exam results between 50 and 80:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;exam_results&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;marks&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This includes both boundaries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;50 → included
65 → included
80 → included
49 → excluded
81 → excluded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could also write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;marks&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
&lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;marks&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That works.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;BETWEEN&lt;/code&gt; is cleaner when working with a range.&lt;/p&gt;

&lt;p&gt;It can also be used with dates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;exam_results&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;exam_date&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="s1"&gt;'2024-03-15'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="s1"&gt;'2024-03-18'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;code&gt;IN&lt;/code&gt;: Checking Against a List
&lt;/h2&gt;

&lt;p&gt;Suppose we want students from Nairobi, Mombasa, or Kisumu.&lt;/p&gt;

&lt;p&gt;We could write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Nairobi'&lt;/span&gt;
&lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Mombasa'&lt;/span&gt;
&lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Kisumu'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Nairobi'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Mombasa'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Kisumu'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;IN&lt;/code&gt; is useful when you have a list of acceptable values.&lt;/p&gt;

&lt;p&gt;It is shorter, easier to read, and saves you from writing a query that looks like it is negotiating with itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;NOT IN&lt;/code&gt;: Excluding Values
&lt;/h2&gt;

&lt;p&gt;Now find students who are not in Form 2 or Form 3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Form 2'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Form 3'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This excludes those two classes.&lt;/p&gt;

&lt;p&gt;Everyone else remains eligible.&lt;/p&gt;

&lt;p&gt;Sometimes the easiest way to describe what you want is to describe what you do not want.&lt;/p&gt;

&lt;p&gt;SQL understands that too.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;LIKE&lt;/code&gt;: Searching for Patterns
&lt;/h2&gt;

&lt;p&gt;Suppose we want students whose first name starts with A or E:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;first_name&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'A%'&lt;/span&gt;
&lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;first_name&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'E%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;%&lt;/code&gt; is a wildcard.&lt;/p&gt;

&lt;p&gt;It means there can be anything after this.&lt;/p&gt;

&lt;p&gt;The assignment also asked for subjects containing the word &lt;code&gt;Studies&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;subjects&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;subject_name&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%Studies%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;%&lt;/code&gt; appears on both sides because the word can occur anywhere in the subject name.&lt;/p&gt;

&lt;p&gt;This is cleaner than manually writing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;subject_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Computer Studies'&lt;/span&gt;
&lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;subject_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Business Studies'&lt;/span&gt;
&lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;subject_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Social Studies'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then remembering another subject later.&lt;/p&gt;

&lt;p&gt;The wildcard does the searching.&lt;/p&gt;

&lt;p&gt;We do not have to manually list every possible value.&lt;/p&gt;

&lt;h2&gt;
  
  
  SECTION E: &lt;code&gt;COUNT(*)&lt;/code&gt; - Let the Database Do the Counting
&lt;/h2&gt;

&lt;p&gt;How many students are currently in Form 3?&lt;/p&gt;

&lt;p&gt;We could count them manually.&lt;/p&gt;

&lt;p&gt;But we have a database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Form 3'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How many exam results have marks of 70 or above?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;exam_results&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;marks&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;COUNT(*)&lt;/code&gt; counts the number of rows that match the condition.&lt;/p&gt;

&lt;p&gt;This is one of those moments where using a computer is a sensible decision.&lt;/p&gt;

&lt;p&gt;The database is already sitting there with the rows.&lt;/p&gt;

&lt;p&gt;Let it count them.&lt;/p&gt;

&lt;p&gt;You have other things to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  SECTION F: &lt;code&gt;CASE WHEN&lt;/code&gt; - Giving Raw Data Some Meaning
&lt;/h2&gt;

&lt;p&gt;The database stores marks.&lt;/p&gt;

&lt;p&gt;People like categories.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;80 and above → Distinction
60–79        → Merit
40–59        → Pass
Below 40     → Fail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can write:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F89btidg598cy4s0zzcm1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F89btidg598cy4s0zzcm1.png" alt="Case when merit" width="799" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the query can give us:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Marks&lt;/th&gt;
&lt;th&gt;Performance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;85&lt;/td&gt;
&lt;td&gt;Distinction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;72&lt;/td&gt;
&lt;td&gt;Merit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;59&lt;/td&gt;
&lt;td&gt;Pass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;39&lt;/td&gt;
&lt;td&gt;Fail&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The important part is that we did not change the original marks.&lt;/p&gt;

&lt;p&gt;If the database stores:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;85
72
59
39
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it still stores:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;85
72
59
39
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The query simply creates a new label while displaying the results.&lt;/p&gt;

&lt;p&gt;That means we can change the classification rules later without rewriting the original marks.&lt;/p&gt;

&lt;p&gt;The raw data stays as it is.&lt;/p&gt;

&lt;p&gt;The interpretation can change.&lt;/p&gt;

&lt;p&gt;We can do the same thing with student classes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F13i052cuyd5syrurh0vp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F13i052cuyd5syrurh0vp.png" alt="case when classes" width="800" height="569"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A student in Form 3 is still in Form 3.&lt;/p&gt;

&lt;p&gt;We are simply creating another way to describe that student.&lt;/p&gt;

&lt;p&gt;No rewriting the original data.&lt;/p&gt;

&lt;p&gt;No creating another spreadsheet.&lt;/p&gt;

&lt;p&gt;The query handles it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Part I Found Most Important
&lt;/h2&gt;

&lt;p&gt;The assignment covered a lot of SQL.&lt;/p&gt;

&lt;p&gt;But the part I kept thinking about was the difference between:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Nairobi'&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;student_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Nairobi'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One updates Esther.&lt;/p&gt;

&lt;p&gt;The other relocates the entire school.&lt;/p&gt;

&lt;p&gt;The same applies to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;exam_results&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;result_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;versus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;exam_results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One removes a canceled exam.&lt;/p&gt;

&lt;p&gt;The other removes every exam result.&lt;/p&gt;

&lt;p&gt;SQL is not difficult because the database is trying to trick you.&lt;/p&gt;

&lt;p&gt;SQL is difficult because the database is perfectly willing to do exactly what you told it to do.&lt;/p&gt;

&lt;p&gt;Even when what you told it to do was a terrible idea.&lt;/p&gt;

&lt;p&gt;So before running an &lt;code&gt;UPDATE&lt;/code&gt; or &lt;code&gt;DELETE&lt;/code&gt;, especially on important data, check what you are about to affect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;student_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then make the change.&lt;/p&gt;

&lt;p&gt;Same condition.&lt;/p&gt;

&lt;p&gt;First, inspect.&lt;/p&gt;

&lt;p&gt;Then, change.&lt;/p&gt;

&lt;p&gt;This is not advanced database engineering.&lt;/p&gt;

&lt;p&gt;It is simply a good habit.&lt;/p&gt;

&lt;p&gt;And good habits are useful when you are tired, it is 2:00 AM, and somebody has just said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“It is a very small change.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Greenwood Academy Taught Me About SQL
&lt;/h2&gt;

&lt;p&gt;The assignment started with an empty database.&lt;/p&gt;

&lt;p&gt;By the end, I had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Created the &lt;code&gt;greenwood_academy&lt;/code&gt; schema.&lt;/li&gt;
&lt;li&gt;Created the &lt;code&gt;students&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;Created the &lt;code&gt;subjects&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;Created the &lt;code&gt;exam_results&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;Added a &lt;code&gt;phone_number&lt;/code&gt; column.&lt;/li&gt;
&lt;li&gt;Renamed &lt;code&gt;credits&lt;/code&gt; to &lt;code&gt;credit_hours&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Removed the &lt;code&gt;phone_number&lt;/code&gt; column.&lt;/li&gt;
&lt;li&gt;Inserted student, subject, and exam result records.&lt;/li&gt;
&lt;li&gt;Updated Esther's city from Nakuru to Nairobi.&lt;/li&gt;
&lt;li&gt;Corrected a mark from 49 to 59.&lt;/li&gt;
&lt;li&gt;Deleted a canceled exam result.&lt;/li&gt;
&lt;li&gt;Filtered data using &lt;code&gt;WHERE&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Combined conditions using &lt;code&gt;AND&lt;/code&gt; and &lt;code&gt;OR&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Used &lt;code&gt;BETWEEN&lt;/code&gt; for ranges.&lt;/li&gt;
&lt;li&gt;Used &lt;code&gt;IN&lt;/code&gt; and &lt;code&gt;NOT IN&lt;/code&gt; for lists.&lt;/li&gt;
&lt;li&gt;Used &lt;code&gt;LIKE&lt;/code&gt; with wildcards.&lt;/li&gt;
&lt;li&gt;Counted records using &lt;code&gt;COUNT(*)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Created performance labels using &lt;code&gt;CASE WHEN&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That sounds like a lot.&lt;/p&gt;

&lt;p&gt;But when broken down, SQL was asking me to do a few very direct things:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE → Make something
INSERT → Put something in
UPDATE → Change something
DELETE → Remove something
SELECT → Show me something
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difficult part was not simply knowing that these commands exist.&lt;/p&gt;

&lt;p&gt;The difficult part was being precise about what they should affect.&lt;/p&gt;

&lt;p&gt;That is where the &lt;code&gt;WHERE&lt;/code&gt; clause quietly becomes one of the most important things in the entire assignment.&lt;/p&gt;

&lt;p&gt;You can learn the syntax.&lt;/p&gt;

&lt;p&gt;You can memorise the commands.&lt;/p&gt;

&lt;p&gt;But at some point, you have to ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What exactly will this query change?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question is probably more useful than memorising another SQL keyword.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I started with an empty PostgreSQL database and a list of questions.&lt;/p&gt;

&lt;p&gt;By the end, I had a better understanding of how the different parts fit together.&lt;/p&gt;

&lt;p&gt;DDL built the structure.&lt;/p&gt;

&lt;p&gt;DML put data into it and changed it.&lt;/p&gt;

&lt;p&gt;DQL let me ask questions about it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BETWEEN&lt;/code&gt;, &lt;code&gt;IN&lt;/code&gt;, &lt;code&gt;NOT IN&lt;/code&gt;, and &lt;code&gt;LIKE&lt;/code&gt; made those questions more specific.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;COUNT(*)&lt;/code&gt; handled the counting.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CASE WHEN&lt;/code&gt; let me add useful labels without changing the original data.&lt;/p&gt;

&lt;p&gt;And &lt;code&gt;WHERE&lt;/code&gt; reminded me that SQL is extremely literal.&lt;/p&gt;

&lt;p&gt;The database will not rescue you from your own query.&lt;/p&gt;

&lt;p&gt;It will not stop and say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I think you meant one row.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It will execute.&lt;/p&gt;

&lt;p&gt;So I have taken one practical rule away from Greenwood Academy:&lt;/p&gt;

&lt;p&gt;Before I run an &lt;code&gt;UPDATE&lt;/code&gt; or a &lt;code&gt;DELETE&lt;/code&gt;, I want to know exactly which rows I am touching.&lt;/p&gt;

&lt;p&gt;Because fixing Esther's city is a normal database task.&lt;/p&gt;

&lt;p&gt;Moving every student in the school to Nairobi is a different kind of meeting.&lt;/p&gt;

&lt;p&gt;And I am not trying to attend that meeting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Surviving SQL is winning, Franklin.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>dbeaver</category>
      <category>database</category>
      <category>sql</category>
    </item>
    <item>
      <title>Commitment Issues: Tracking Changes, Romantic Promises, and Surviving the Git Staging Crate</title>
      <dc:creator>Faith Njenga</dc:creator>
      <pubDate>Sun, 12 Jul 2026 20:29:09 +0000</pubDate>
      <link>https://dev.to/ms_njenga/commitment-issues-tracking-changes-romantic-promises-and-surviving-the-git-staging-crate-152k</link>
      <guid>https://dev.to/ms_njenga/commitment-issues-tracking-changes-romantic-promises-and-surviving-the-git-staging-crate-152k</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Commitment is a funny thing.&lt;/p&gt;

&lt;p&gt;Some people date for years before making it official. Some rush into relationships they regret two weeks later. And then there are those people who keep saying, “Let’s just see where this goes,” until everyone involved is emotionally exhausted.&lt;/p&gt;

&lt;p&gt;Believe it or not, Git has the exact same personality.&lt;/p&gt;

&lt;p&gt;If you’ve never heard of Git before, think of it as a really smart time machine for your code. It remembers every meaningful change you make, lets you revisit older versions when things go wrong, and makes it possible for multiple developers to work on the same project without accidentally overwriting each other’s work. In short, Git is a version control system and one of the most important tools you’ll use as a developer.&lt;/p&gt;

&lt;p&gt;But Git doesn’t commit to every little change you make.&lt;/p&gt;

&lt;p&gt;Every time you edit a file, Git looks at your changes and asks, “So… are we serious, or are we just experimenting?” If you’re not ready to commit, your changes wait patiently in the staging area,the software equivalent of “It’s complicated.” If you are ready, Git wraps everything up into a commit: a permanent promise that says, “Yes, I meant to do this.”&lt;/p&gt;

&lt;p&gt;The problem is that most beginners are taught Git like they’re preparing for a spelling bee.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add
git commit
git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Memorize the commands.&lt;br&gt;
Don’t ask questions.&lt;br&gt;
Hope nothing catches fire.&lt;/p&gt;

&lt;p&gt;Then, the first time they accidentally commit the wrong files, forget to stage something important, or stare at git status like it’s judging their life choices, panic sets in.&lt;/p&gt;

&lt;p&gt;Here’s the secret: &lt;strong&gt;Git isn’t complicated because the commands are difficult. It’s confusing because no one explains why they exist.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So in this article, we’re going to stop memorizing magic words and start thinking like Git. We’ll open the mysterious staging crate, decide which changes deserve commitment, rescue a few questionable life decisions, and discover why version control is less about remembering commands and more about making good choices.&lt;/p&gt;

&lt;p&gt;Because in Git-as in relationships not everything you change deserves a lifelong commitment.&lt;/p&gt;


&lt;h2&gt;
  
  
  Episode 1: "So... What Are We?" (&lt;code&gt;git init&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;Picture this.&lt;/p&gt;

&lt;p&gt;You've met someone amazing. You've exchanged numbers. You've talked for hours. You've even started imagining your future together.&lt;/p&gt;

&lt;p&gt;But then a friend asks,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Wait... are you two actually together?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Cue the awkward silence.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Because until someone makes it official, you're just... existing in each other's lives.&lt;/p&gt;

&lt;p&gt;Your project has the same identity crisis.&lt;/p&gt;

&lt;p&gt;You create a new folder. You add a few files. Maybe you've already written hundreds of lines of code. It looks like a software project, smells like a software project, and behaves like a software project.&lt;/p&gt;

&lt;p&gt;Git, however, looks at it, shrugs, and says,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"I've literally never seen this project before."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's where this little command changes everything.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4bwpc8ha6008amvecsng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4bwpc8ha6008amvecsng.png" alt="gitinit" width="796" height="88"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The moment you hit &lt;strong&gt;Enter&lt;/strong&gt;, your project finally introduces itself.&lt;/p&gt;

&lt;p&gt;Git quietly creates a hidden folder called &lt;strong&gt;&lt;code&gt;.git&lt;/code&gt;&lt;/strong&gt; a place you'll almost never open but one you'll rely on every single day.&lt;/p&gt;

&lt;p&gt;Think of it as the relationship archive.&lt;/p&gt;

&lt;p&gt;Every promise you keep (commits), every detour you take (branches), every reunion after a disagreement (merges), and every embarrassing decision you'd rather pretend never happened... Git stores it all in there.&lt;/p&gt;

&lt;p&gt;It's basically that friend who remembers &lt;strong&gt;everything&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Remember that tiny CSS change you made three weeks ago at 2:17 a.m.? Yeah... I still have it."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And if one day you decide to delete the &lt;strong&gt;&lt;code&gt;.git&lt;/code&gt;&lt;/strong&gt; folder?&lt;/p&gt;

&lt;p&gt;Congratulations.&lt;/p&gt;

&lt;p&gt;You didn't delete your project.&lt;/p&gt;

&lt;p&gt;You just convinced Git that the two of you never met.&lt;/p&gt;




&lt;h2&gt;
  
  
  Episode 2: The Honest Bestie (&lt;code&gt;git status&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;Every relationship has that one best friend.&lt;/p&gt;

&lt;p&gt;The one who somehow knows &lt;strong&gt;everything&lt;/strong&gt; before you tell them.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Girl... I saw what happened."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"You're leaving out the important part."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Who exactly is this?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;They're not being nosy.&lt;/p&gt;

&lt;p&gt;They're just trying to save you from making questionable decisions.&lt;/p&gt;

&lt;p&gt;Git is that best friend.&lt;/p&gt;

&lt;p&gt;Ever since you made things official with &lt;code&gt;git init&lt;/code&gt;, Git has been quietly paying attention to your project. It isn't changing anything or making decisions for you it simply watches, remembers, and waits for your next move.&lt;/p&gt;

&lt;p&gt;So naturally, the first thing you should ask your bestie is,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Okay... what's the situation?"&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpm5m2w1ib2y429gnmyzn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpm5m2w1ib2y429gnmyzn.png" alt="gitstatus1" width="800" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Git takes one look around your project and gives you the unfiltered truth.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"I noticed you've brought some new people into your life..."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"...care to introduce me?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those red filenames aren't errors.&lt;/p&gt;

&lt;p&gt;They're &lt;strong&gt;untracked files&lt;/strong&gt; files that Git has noticed but hasn't officially been introduced to yet.&lt;/p&gt;

&lt;p&gt;Think of it this way.&lt;/p&gt;

&lt;p&gt;You've started hanging out with new friends, but you've never brought them around your bestie. So when your best friend sees them for the first time, they're naturally like,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Wait... who are these?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Until you make those introductions, Git won't remember those files or include them in your project's history. If they disappear tomorrow, Git can't help you because, as far as it's concerned...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"I've never met them."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, let's address the one person who always shows up uninvited.&lt;/p&gt;

&lt;p&gt;Take a look at the list again.&lt;/p&gt;

&lt;p&gt;See &lt;strong&gt;&lt;code&gt;.ipynb_checkpoints/&lt;/code&gt;&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;If you use Jupyter Notebooks, you've probably met this little troublemaker. Every time you save your notebook, Jupyter quietly creates checkpoint files behind the scenes as a backup.&lt;/p&gt;

&lt;p&gt;It's useful.&lt;/p&gt;

&lt;p&gt;It's harmless.&lt;/p&gt;

&lt;p&gt;But it has absolutely no business following you to GitHub.&lt;/p&gt;

&lt;p&gt;It's like bringing your best friend to meet your family... and they show up with their cousin, their neighbor, and someone's emotional support hamster.&lt;/p&gt;

&lt;p&gt;Nobody asked for all that.&lt;/p&gt;




&lt;h2&gt;
  
  
  Episode 3: "Before You Make It Official..." (&lt;code&gt;git add&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;You know what happens after you've introduced someone to your best friend?&lt;/p&gt;

&lt;p&gt;The interrogation begins.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"So... do you actually like them?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Are they staying?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Should I bother learning their name?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Is this another one of your 'it's different this time' situations?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Your bestie isn't being dramatic.&lt;/p&gt;

&lt;p&gt;They're just trying to figure out who deserves a permanent place in your life.&lt;/p&gt;

&lt;p&gt;Git has reached that exact moment.&lt;/p&gt;

&lt;p&gt;In the last episode, &lt;code&gt;git status&lt;/code&gt; showed Git everyone hanging around your project. It noticed the new files, gave you the side-eye, and asked,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Okay... who exactly are these people?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now it's waiting for your answer.&lt;/p&gt;

&lt;p&gt;This is where the &lt;strong&gt;staging area&lt;/strong&gt; comes in.&lt;/p&gt;

&lt;p&gt;Think of it as the beautifully crafted wooden crate sitting on your desk.&lt;/p&gt;

&lt;p&gt;It's not the commitment box.&lt;/p&gt;

&lt;p&gt;Not yet.&lt;/p&gt;

&lt;p&gt;It's simply where you place the files you're &lt;strong&gt;considering&lt;/strong&gt; committing.&lt;/p&gt;

&lt;p&gt;Inside the crate are envelopes labelled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Maybe later&lt;/li&gt;
&lt;li&gt; Not ready yet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sound familiar?&lt;/p&gt;

&lt;p&gt;That's because staging isn't commitment.&lt;/p&gt;

&lt;p&gt;It's &lt;strong&gt;intention&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's you telling Git,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"These are the changes I'm thinking about making official."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Maybe you're confident and want to stage everything.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fep7dkdnej45g52ja3o5c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fep7dkdnej45g52ja3o5c.png" alt="gitadd--all" width="800" height="55"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Git happily picks up every new file, every modified file, and every deleted file, placing them neatly into the staging crate.&lt;/p&gt;

&lt;p&gt;You'll also see developers use the shorter version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nt"&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl4z3eklx63orm4bp4wv6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl4z3eklx63orm4bp4wv6.png" alt="gitaddA" width="800" height="52"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Same result.&lt;/p&gt;

&lt;p&gt;Just fewer keystrokes.&lt;/p&gt;

&lt;p&gt;Now suppose you're standing inside your project and simply want Git to gather everything from &lt;strong&gt;right here&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's where the famous little dot comes in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa0g7csfhx31awfbhy161.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa0g7csfhx31awfbhy161.png" alt="GITADD" width="796" height="65"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That tiny &lt;code&gt;.&lt;/code&gt; simply means,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Start from this folder and bring everything below it."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you're already at your project's root directory, &lt;code&gt;git add .&lt;/code&gt; will usually give you the same result as the previous commands.&lt;/p&gt;

&lt;p&gt;Now imagine your bestie peeks inside the staging crate.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Okay... these are the people you're serious about?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You nod.&lt;/p&gt;

&lt;p&gt;Your bestie smiles.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Cool."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Just remember... putting them in the crate doesn't mean you're engaged."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Exactly.&lt;/p&gt;

&lt;p&gt;Nothing has been committed yet.&lt;/p&gt;

&lt;p&gt;The letters are written.&lt;/p&gt;

&lt;p&gt;The envelopes are packed.&lt;/p&gt;

&lt;p&gt;The crate is full.&lt;/p&gt;

&lt;p&gt;But the promise hasn't been made.&lt;/p&gt;

&lt;p&gt;That... happens in the next episode.&lt;/p&gt;




&lt;h2&gt;
  
  
  Episode 4: The Plot Twist - "Wait... They're Coming Too?"
&lt;/h2&gt;

&lt;p&gt;You've spent all this time deciding who belongs in the staging crate.&lt;/p&gt;

&lt;p&gt;Your bestie helped.&lt;/p&gt;

&lt;p&gt;The letters are neatly packed.&lt;/p&gt;

&lt;p&gt;Everything looks perfect.&lt;/p&gt;

&lt;p&gt;So, just before making the biggest commitment of your Git journey, you ask one last question.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Bestie... can you check the crate one more time?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Git happily obliges.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fijgn1skqgi56ph0ewhd4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fijgn1skqgi56ph0ewhd4.png" alt="gitstatusafteradding" width="800" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything is green.&lt;/p&gt;

&lt;p&gt;At first, you're relieved.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Yes! We did it!"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then your bestie squints at the list.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"...Hold on."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Why is &lt;em&gt;that&lt;/em&gt; coming with us?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You lean over the crate.&lt;/p&gt;

&lt;p&gt;Inside, alongside your Python scripts and notebooks, you spot...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A massive software installer ZIP file.&lt;/li&gt;
&lt;li&gt;An MP3 music file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.ipynb_checkpoints/&lt;/code&gt; quietly pretending it belongs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Awkward.&lt;/p&gt;

&lt;p&gt;This is what happens when you stage &lt;strong&gt;everything&lt;/strong&gt; without checking what's inside the crate.&lt;/p&gt;

&lt;p&gt;It's the Git equivalent of sending wedding invitations to everyone in your contacts list...&lt;/p&gt;

&lt;p&gt;...including your ex.&lt;/p&gt;

&lt;p&gt;...your nail-tech.&lt;/p&gt;

&lt;p&gt;...and the plumber who fixed your sink three years ago.&lt;/p&gt;

&lt;p&gt;Technically, they'll all show up.&lt;/p&gt;

&lt;p&gt;But should they?&lt;/p&gt;

&lt;p&gt;Absolutely not.&lt;/p&gt;

&lt;p&gt;If you commit these files and push them to GitHub, your repository becomes unnecessarily large, cloning takes longer, and anyone reviewing your project will immediately wonder,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Did they actually mean to include all of this?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The good news?&lt;/p&gt;

&lt;p&gt;Git understands that we all make questionable decisions.&lt;/p&gt;

&lt;p&gt;It even gives you a graceful way to unpack the entire staging crate without throwing away your actual files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;--cached&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think of this command as your best friend standing at the door collecting invitations.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Nope... you're not coming."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"You either."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Definitely not you."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The files stay safely on your computer.&lt;/p&gt;

&lt;p&gt;Git simply removes them from the staging area, giving you the chance to pack the crate again but this time with a little more intention.&lt;/p&gt;

&lt;p&gt;Because here's the thing about commitment...&lt;/p&gt;

&lt;p&gt;Changing your mind &lt;strong&gt;before&lt;/strong&gt; you make the promise is a lot easier than trying to explain yourself afterward.&lt;/p&gt;




&lt;h2&gt;
  
  
  Episode 5: "So... Are We Official Now?" (&lt;code&gt;git commit&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;The crate is packed.&lt;/p&gt;

&lt;p&gt;Your bestie has checked the guest list twice.&lt;/p&gt;

&lt;p&gt;The random ZIP file has been politely uninvited.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.ipynb_checkpoints/&lt;/code&gt; finally got the hint.&lt;/p&gt;

&lt;p&gt;Everything inside the staging crate is exactly where it should be.&lt;/p&gt;

&lt;p&gt;Your bestie looks at you.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Last chance."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Are you absolutely sure these are the changes you want to keep forever?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You take one final look.&lt;/p&gt;

&lt;p&gt;You smile.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Yeah... I'm ready."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is the moment Git has been waiting for.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"First commit"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a single command, Git carefully closes the staging crate.&lt;/p&gt;

&lt;p&gt;It seals every envelope with wax.&lt;/p&gt;

&lt;p&gt;It writes today's story into its diary.&lt;/p&gt;

&lt;p&gt;And just like that...&lt;/p&gt;

&lt;p&gt;Your changes become part of history.&lt;/p&gt;

&lt;p&gt;This is called a &lt;strong&gt;commit&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Think of a commit as a photograph.&lt;/p&gt;

&lt;p&gt;Not of what your project &lt;strong&gt;will become&lt;/strong&gt;...&lt;/p&gt;

&lt;p&gt;...but of exactly what it looked like at &lt;strong&gt;this very moment&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No matter how many changes you make tomorrow, next week, or six months from now, Git can always return to this snapshot.&lt;/p&gt;

&lt;p&gt;That's why commits are so powerful.&lt;/p&gt;

&lt;p&gt;They're promises to your future self.&lt;/p&gt;

&lt;p&gt;They're your way of saying,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"I know this version works."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"I know why I made these changes."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"If I ever mess things up, I can always come back here."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And before you start thinking,&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Great! My code is finally on GitHub!"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Not so fast.&lt;/p&gt;

&lt;p&gt;Your commit lives &lt;strong&gt;only on your computer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's like writing a heartfelt love letter, sealing it in an envelope, and placing it safely inside your desk drawer.&lt;/p&gt;

&lt;p&gt;The promise is real.&lt;/p&gt;

&lt;p&gt;It's official.&lt;/p&gt;

&lt;p&gt;But nobody else knows about it...&lt;/p&gt;

&lt;p&gt;Yet.&lt;/p&gt;




&lt;h2&gt;
  
  
  Episode 6: The "We Need to Talk" Conversation (&lt;code&gt;git switch&lt;/code&gt;, &lt;code&gt;git diff&lt;/code&gt; &amp;amp; &lt;code&gt;git restore&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;Every healthy relationship has one.&lt;/p&gt;

&lt;p&gt;The conversation.&lt;/p&gt;

&lt;p&gt;Not the breakup.&lt;/p&gt;

&lt;p&gt;Not the proposal.&lt;/p&gt;

&lt;p&gt;The one that starts with,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Can we talk?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Maybe someone wants to rephrase a promise.&lt;/p&gt;

&lt;p&gt;Maybe someone realizes they could have said something better.&lt;/p&gt;

&lt;p&gt;Maybe they're just trying to figure things out.&lt;/p&gt;

&lt;p&gt;The good news?&lt;/p&gt;

&lt;p&gt;In Git, you're allowed to have those conversations without ruining the original relationship.&lt;/p&gt;

&lt;p&gt;That's exactly what &lt;strong&gt;branches&lt;/strong&gt; are for.&lt;/p&gt;

&lt;p&gt;Think of a branch as an alternate timeline.&lt;/p&gt;

&lt;p&gt;Instead of rewriting history, Git lets you create a safe little universe where you can experiment, make mistakes, and change your mind, all without touching your stable project.&lt;/p&gt;

&lt;p&gt;So let's create one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch &lt;span class="nt"&gt;-c&lt;/span&gt; remove_promise
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbcfeb5yltu3m8uiqj1yn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbcfeb5yltu3m8uiqj1yn.png" alt="remove_promise" width="800" height="67"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your bestie raises an eyebrow.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"So... you're telling me you're about to edit the promise?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Relax.&lt;/p&gt;

&lt;p&gt;We're not changing the original.&lt;/p&gt;

&lt;p&gt;We're just exploring a &lt;em&gt;"What if?"&lt;/em&gt; scenario.&lt;/p&gt;

&lt;p&gt;Inside our &lt;code&gt;index.html&lt;/code&gt;, we tweak the heartfelt letter.&lt;/p&gt;

&lt;p&gt;Nothing dramatic.&lt;/p&gt;

&lt;p&gt;Just enough to make Git notice.&lt;/p&gt;

&lt;p&gt;Before doing anything else, let's ask our honest bestie what they think.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4neh8yb6c5xx4i5lmjqt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4neh8yb6c5xx4i5lmjqt.png" alt="gitstatus" width="800" height="142"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Git immediately notices the change.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"I saw that."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"You changed something... but you haven't told me to remember it yet."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's all &lt;code&gt;git status&lt;/code&gt; is doing.&lt;/p&gt;

&lt;p&gt;It's keeping you honest.&lt;/p&gt;

&lt;p&gt;Now imagine you stare at your edit for a minute and suddenly think,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What was I even trying to say?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We've all been there.&lt;/p&gt;

&lt;p&gt;Fortunately, Git doesn't judge questionable decisions.&lt;/p&gt;

&lt;p&gt;It simply offers an escape route.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git restore index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think of &lt;code&gt;git restore&lt;/code&gt; as crumpling up the draft letter before anyone reads it.&lt;/p&gt;

&lt;p&gt;The edits disappear.&lt;/p&gt;

&lt;p&gt;Your last committed version remains untouched, as if the conversation never happened.&lt;/p&gt;

&lt;p&gt;But let's pretend we actually like our new wording.&lt;/p&gt;

&lt;p&gt;How do we see &lt;strong&gt;exactly&lt;/strong&gt; what changed?&lt;/p&gt;

&lt;p&gt;That's where &lt;code&gt;git diff&lt;/code&gt; becomes your bestie's favorite gossip tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxiuwkcm40ranb9mdiqsq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxiuwkcm40ranb9mdiqsq.png" alt="diff" width="800" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Git opens the receipts.&lt;/p&gt;

&lt;p&gt;No guessing.&lt;/p&gt;

&lt;p&gt;No "I think I changed this."&lt;/p&gt;

&lt;p&gt;Just the facts.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;red&lt;/strong&gt; line, marked with a &lt;code&gt;-&lt;/code&gt;, shows what you're saying goodbye to.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;green&lt;/strong&gt; line, marked with a &lt;code&gt;+&lt;/code&gt;, shows the new version waiting to take its place.&lt;/p&gt;

&lt;p&gt;In our case, we upgraded the promise by adding the word &lt;strong&gt;"always."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One tiny word.&lt;/p&gt;

&lt;p&gt;One huge difference.&lt;/p&gt;

&lt;p&gt;And before we make that promise official, Git gives us one final chance to review every single change.&lt;/p&gt;

&lt;p&gt;Because the strongest relationships and the strongest codebases aren't built by never making mistakes.&lt;/p&gt;

&lt;p&gt;They're built by being able to see exactly what changed before making another commitment.&lt;/p&gt;




&lt;h2&gt;
  
  
  Episode 7: The Reunion (&lt;code&gt;git merge&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;Every couple reaches this moment.&lt;/p&gt;

&lt;p&gt;You've had the difficult conversation.&lt;/p&gt;

&lt;p&gt;You've rewritten the letter.&lt;/p&gt;

&lt;p&gt;You've taken some time apart to figure things out.&lt;/p&gt;

&lt;p&gt;Now comes the big question.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Can we bring this back into the relationship?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Remember, all of our edits have been living safely on a separate branch. Think of it as taking a weekend getaway to clear your head. The &lt;code&gt;main&lt;/code&gt; branch has been patiently waiting at home, completely untouched.&lt;/p&gt;

&lt;p&gt;Before the reunion can happen, we need to go back home.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your bestie smiles.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Welcome back."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now it's time to bring everything we worked on back into the main story.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git merge remove_promise
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fapwzsuj4by6ohcy0cheu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fapwzsuj4by6ohcy0cheu.png" alt="merging" width="799" height="103"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Git takes one look at both branches.&lt;/p&gt;

&lt;p&gt;Then it shrugs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Well... that was easy."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since nobody touched the &lt;code&gt;main&lt;/code&gt; branch while we were away, Git doesn't have to play relationship counselor.&lt;/p&gt;

&lt;p&gt;There are no arguments.&lt;/p&gt;

&lt;p&gt;No awkward conversations.&lt;/p&gt;

&lt;p&gt;No one saying,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"That's not what I meant."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead, Git simply moves the &lt;code&gt;main&lt;/code&gt; branch forward until it catches up with your new commit.&lt;/p&gt;

&lt;p&gt;This is called a &lt;strong&gt;fast-forward merge&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Think of it like coming back from a weekend trip.&lt;/p&gt;

&lt;p&gt;Your family didn't repaint the house.&lt;/p&gt;

&lt;p&gt;Nobody rearranged the furniture.&lt;/p&gt;

&lt;p&gt;Everything is exactly where you left it.&lt;/p&gt;

&lt;p&gt;So fitting back in is effortless.&lt;/p&gt;

&lt;p&gt;Your upgraded promise is now part of the main story, and Git quietly records another successful chapter in its diary.&lt;/p&gt;

&lt;p&gt;Your bestie closes the diary with a satisfied smile.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Perfect."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Everything is finally where it belongs."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You smile back...&lt;/p&gt;

&lt;p&gt;Then your bestie asks one last question.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"...So, are you planning to keep this relationship a secret?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because right now, everything we've done exists &lt;strong&gt;only on your computer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Our story is complete.&lt;/p&gt;

&lt;p&gt;Our commits are safe.&lt;/p&gt;

&lt;p&gt;Our branches are merged.&lt;/p&gt;

&lt;p&gt;But the rest of the world still has no idea our project exists.&lt;/p&gt;

&lt;p&gt;Let's change that.&lt;/p&gt;




&lt;h2&gt;
  
  
  Episode 8: Going Public (&lt;code&gt;git push&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;So far, our entire love story has been wonderfully... private.&lt;/p&gt;

&lt;p&gt;We've met Git.&lt;/p&gt;

&lt;p&gt;We've introduced the important files.&lt;/p&gt;

&lt;p&gt;We've packed the staging crate.&lt;/p&gt;

&lt;p&gt;We've made our commitment.&lt;/p&gt;

&lt;p&gt;We've even survived a little relationship drama and reunited stronger than before.&lt;/p&gt;

&lt;p&gt;But there's one tiny problem.&lt;/p&gt;

&lt;p&gt;Everything we've done still lives &lt;strong&gt;only on our laptop&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's like getting engaged...&lt;/p&gt;

&lt;p&gt;...and forgetting to tell your family.&lt;/p&gt;

&lt;p&gt;Before we can share our project with the world, Git needs to know &lt;strong&gt;where&lt;/strong&gt; the world is.&lt;/p&gt;

&lt;p&gt;So head over to GitHub, create a repository, and copy its URL.&lt;/p&gt;

&lt;p&gt;Then introduce your local repository to its new home.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvxeqf6jr9fhhjj1rstol.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvxeqf6jr9fhhjj1rstol.png" alt="shippingtogithub" width="800" height="53"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll notice we give GitHub a nickname:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;origin&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Think of it as saving someone's contact in your phone as &lt;strong&gt;"Bestie"&lt;/strong&gt; instead of memorizing their entire phone number.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;origin&lt;/code&gt; is simply a friendly alias for your GitHub repository, making it much easier to communicate with later.&lt;/p&gt;

&lt;p&gt;Now comes the moment we've been building toward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With one command, your local story leaves your laptop for the very first time.&lt;/p&gt;

&lt;p&gt;Your commits travel to GitHub.&lt;/p&gt;

&lt;p&gt;Your repository finally has an online home.&lt;/p&gt;

&lt;p&gt;And your project is no longer just &lt;strong&gt;your&lt;/strong&gt; story.&lt;/p&gt;

&lt;p&gt;It's a story others can now see, clone, learn from, and contribute to.&lt;/p&gt;

&lt;p&gt;Our relationship is officially public.&lt;/p&gt;

&lt;p&gt;But don't get too comfortable...&lt;/p&gt;

&lt;p&gt;Because sharing your work with the world introduces a whole new kind of drama.&lt;/p&gt;

&lt;p&gt;Pull requests.&lt;/p&gt;

&lt;p&gt;Remote repositories.&lt;/p&gt;

&lt;p&gt;Authentication.&lt;/p&gt;

&lt;p&gt;Merge conflicts.&lt;/p&gt;

&lt;p&gt;And teammates who somehow edit the exact same line you were working on.&lt;/p&gt;

&lt;p&gt;We'll save that tea for the next chapter.&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
      <category>analytics</category>
      <category>dataengineering</category>
    </item>
    <item>
      <title>Is It a Crime to Want a Flawless Connection? Mastering Local and Cloud Databases in Power BI</title>
      <dc:creator>Faith Njenga</dc:creator>
      <pubDate>Tue, 07 Jul 2026 00:34:24 +0000</pubDate>
      <link>https://dev.to/ms_njenga/is-it-a-crime-to-want-a-flawless-connection-mastering-local-and-cloud-databases-in-power-bi-3l6j</link>
      <guid>https://dev.to/ms_njenga/is-it-a-crime-to-want-a-flawless-connection-mastering-local-and-cloud-databases-in-power-bi-3l6j</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmivu1clvllukc41uoxrm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmivu1clvllukc41uoxrm.png" alt="COVER1" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  INTRODUCTION
&lt;/h2&gt;

&lt;p&gt;When you first start learning Power BI, life is relatively simple. You click "Get Data," select a spreadsheet or a CSV file sitting on your desktop, and start building charts. It’s a comfortable bubble. &lt;br&gt;
But as you start working on bigger projects, you quickly realize a hard truth: in the real world, most data doesn't live in loose spreadsheets on your desktop. It lives inside database servers.&lt;/p&gt;

&lt;p&gt;The moment you try to step out of your comfort zone and connect Power BI to a database, the setup process can feel incredibly intimidating. Connecting to a database running right on your own computer is usually pretty smooth. But the second you try to connect to a secure cloud platform like Aiven PostgreSQL, Power BI will often drop a massive roadblock right in your face: &lt;strong&gt;The SSL Certificate Error&lt;/strong&gt;.&lt;br&gt;
Suddenly, you are staring at a scary security alert, wondering why a cloud server won't let you access your data. If you are tired of hitting connection walls and just want your tools to talk to each other, don't panic. You don't need to be a senior database engineer or a coding expert to fix this.&lt;br&gt;
In this beginner-friendly guide, we are going to break down the exact, click-by-click steps to handle simple local connections and show you the ultimate Windows trick to make your computer automatically trust your cloud database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: Moving Data into the Database (DBeaver Import)
&lt;/h2&gt;

&lt;p&gt;Before Power BI can turn your data into visual charts, we need to upload our file into our database. We will use a free tool called &lt;code&gt;DBeaver&lt;/code&gt; to act as our database manager. Think of DBeaver as a file explorer, but specifically built for databases. It lets us drag, drop, and view our tables without writing a single line of code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1.1: Logging Into Your Database
&lt;/h3&gt;

&lt;p&gt;Whether your database is running quietly on your own laptop or hosted online via Aiven, DBeaver needs to know where to find it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Open DBeaver and click the Plug Icon (New Database Connection) in the top-left corner.&lt;/li&gt;
&lt;li&gt; Select PostgreSQL from the list of database types and click Next.&lt;/li&gt;
&lt;li&gt; Look at your database settings (either your local installation details or your Aiven Console dashboard) and fill in the blanks:&lt;/li&gt;
&lt;li&gt;Host: Use &lt;code&gt;localhost&lt;/code&gt; or &lt;code&gt;127.0.0.1&lt;/code&gt; for your own computer, or paste the long server link provided by Aiven.Port: Type &lt;code&gt;5432&lt;/code&gt; for local setups, or &lt;code&gt;24306&lt;/code&gt; for Aiven cloud instances.&lt;/li&gt;
&lt;li&gt;Database: Type the name of your target database (the default local one is usually called &lt;code&gt;postgres&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Username &amp;amp; Password: Type in your database login keys.&lt;/li&gt;
&lt;li&gt;Click Test Connection. Once a little box pops up with a green success message, click Finish.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcpyd0uey1ewthy1n4d1a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcpyd0uey1ewthy1n4d1a.png" alt="local connection" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1.2: Creating a Folder and Importing Your File
&lt;/h3&gt;

&lt;p&gt;To keep our data organized, we don't want to dump our tables into a messy public folder. Let's create a clean, dedicated space called a Schema. In DBeaver’s left sidebar, expand your database connection.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Right-click on the word Schemas. Select Create New Schema. &lt;/li&gt;
&lt;li&gt;Right-click your brand-new schema folder. Select Import Data. Input file and click Next.&lt;/li&gt;
&lt;li&gt;Click the folder icon, browse your computer, and select the data file you want to upload.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhkc4jk84h5b3jhqp6691.png" alt="folder" width="800" height="450"&gt;
&lt;/li&gt;
&lt;li&gt;Click Next through the settings, DBeaver will automatically look at your file and fit the right column structures for you. Click Proceed to execute the upload.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F852k881weqhf4ykfg2xr.png" alt="before importing" width="800" height="450"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Part 2: The Easy Road (Connecting to a Local Database)
&lt;/h2&gt;

&lt;p&gt;Now, let's open Power BI Desktop. We will start with the easiest, most stress-free connection scenario: linking up to a database running natively right on your own machine (localhost). Because this traffic never leaves your computer, Windows automatically trusts it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Launch Power BI Desktop and open a blank report canvas.&lt;/li&gt;
&lt;li&gt;On the top Home ribbon, click the &lt;strong&gt;Get Data button -&amp;gt; select More -&amp;gt; choose PostgreSQL database.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;In the Server input box, type your database location using a &lt;code&gt;host:port&lt;/code&gt; (for a local setup, this is usually &lt;code&gt;localhost:5432&lt;/code&gt;or &lt;code&gt;127.0.0.1:5432&lt;/code&gt;). Type your database name in the box below it.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjshmx3u98kuaj8stfppc.png" alt="database" width="800" height="450"&gt;
&lt;/li&gt;
&lt;li&gt;Choose Import as your data connectivity mode (this pulls a copy of the data into Power BI so your charts load incredibly fast) and click OK.&lt;/li&gt;
&lt;li&gt;Switch to the Database credentials tab on the left sidebar, enter your database username and password, and click Connect.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6o3swvxx8dvxuvv46ah8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6o3swvxx8dvxuvv46ah8.png" alt="password" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your tables will instantly pop up in the Navigator window, ready to be loaded into your report&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fssews8ij5wwbiyi73gty.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fssews8ij5wwbiyi73gty.png" alt="pop-out" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 3: The Cloud Roadblock (Bypassing Aiven's Security Alert)
&lt;/h2&gt;

&lt;p&gt;Now, try taking your long Aiven cloud host string, pasting it into that exact same Power BI connection box, and hitting connect. It will fail instantly.&lt;br&gt;
Instead of seeing your tables, Power BI will flash a frustrating SSL/Security Error on your screen.&lt;br&gt;
Why does this happen? Cloud databases like Aiven sit on the internet outside your home network. To protect your information, they force everything to be strictly encrypted. Power BI relies entirely on your Windows operating system to check if a cloud connection is safe. Because Windows doesn't recognize Aiven out-of-the-box, it panics and blocks the pipeline.&lt;br&gt;
To break through this wall, we just need to download a digital security passport (a CA Certificate) from Aiven and slide it into your Windows security vault. Once Windows trusts it, Power BI will too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3.1: Downloading the Security Passport
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open your web browser and log into your Aiven.io console.&lt;/li&gt;
&lt;li&gt;Click on your running PostgreSQL service page.&lt;/li&gt;
&lt;li&gt;Scroll down to the Connection Information panel on your dashboard.&lt;/li&gt;
&lt;li&gt;Locate the CA Certificate block and click the Download button. This saves a small file called ca.pem to your machine.&lt;/li&gt;
&lt;li&gt;Pro-Tip: Don't leave this file in your temporary Downloads folder. Move it to a permanent folder on your computer, because Windows needs to look at this file in the background every single time your Power BI charts refresh.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F58109dxbp89y61152ose.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F58109dxbp89y61152ose.png" alt="Download ca cert" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3.2: Slipping the Certificate into the Windows Vault
&lt;/h3&gt;

&lt;p&gt;Now, we explicitly tell Windows that this cloud database is completely safe.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click your Windows taskbar search tool, type "Manage computer certificates" (or press Win + R, type certlm.msc, and press Enter) to open the Certificate Manager.&lt;/li&gt;
&lt;li&gt;On the left side panel, locate and expand the folder named &lt;strong&gt;Trusted Root Certification Authorities&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Right-click the underlying &lt;strong&gt;Certificates sub-folder -&amp;gt; Go to All Tasks -&amp;gt; Click Import....&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Step into the wizard and click Next. When the file browser opens, change the extension dropdown in the bottom-right corner from "X.509" to "All Files (.)" otherwise, your ca.pem file will stay invisible&lt;/li&gt;
&lt;li&gt;Select your ca.pem file, click Next through the default locations, and click Finish. Click Yes on the dramatic Windows security warning pop-up.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9zd395typk8rvnzlp797.png" alt="cert" width="800" height="450"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Part 4: The Flawless Cloud Connection
&lt;/h2&gt;

&lt;p&gt;With your Windows operating system now validating the security handshake in the background, the connection barrier completely disappears.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Launch Power BI Desktop and open a blank report canvas.&lt;/li&gt;
&lt;li&gt;On the top Home ribbon, click the &lt;strong&gt;Get Data button -&amp;gt; select More -&amp;gt; choose PostgreSQL database.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Input your Aiven cloud host and port details into the server field.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhr6a2zmppmpns0v5z90x.png" alt="aiven host and port" width="800" height="450"&gt;
&lt;/li&gt;
&lt;li&gt;The Cloud Switch: Because your machine now holds the matching validation key, check the "Use encrypted connection" box.&lt;/li&gt;
&lt;li&gt;Click OK, pivot to the Database credentials tab on the left sidebar, enter your administrative username (avnadmin), and paste your cloud service password.&lt;/li&gt;
&lt;li&gt;Hit Connect.
The data gates open instantly. The Navigator interface will open up beautifully, displaying your custom cloud schema and your loaded tables completely free of security alerts and ready to be turned into stunning dashboards.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6g0v2i1yybfhfh17tp48.png" alt="navigation pane" width="800" height="450"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Stepping up from basic flat files to structured database servers can feel like a steep learning curve, but it is one of the most valuable skills you can learn. Local connections are fantastic for practicing and testing things quickly on your own machine. But learning how to work with certificates and cloud encryption layers is what prepares you for real-world data environments. You don't need to be a coding genius to build secure pipelines, you just need to know how to configure your security lanes&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>database</category>
      <category>dbeaver</category>
      <category>cloudstorage</category>
    </item>
    <item>
      <title>Relationships Are Hard (Except in Power BI Data Modeling)</title>
      <dc:creator>Faith Njenga</dc:creator>
      <pubDate>Tue, 30 Jun 2026 15:04:34 +0000</pubDate>
      <link>https://dev.to/ms_njenga/relationships-are-hard-except-in-power-bi-data-modeling-27cp</link>
      <guid>https://dev.to/ms_njenga/relationships-are-hard-except-in-power-bi-data-modeling-27cp</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw4p6v9qnmifak9g7s6iu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw4p6v9qnmifak9g7s6iu.png" alt="Cover Image" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;u&gt;INTRODUCTION&lt;/u&gt;
&lt;/h2&gt;

&lt;p&gt;Power BI is mainly associated with the creation of beautiful, interactive dashboards and reports, but did you know that it has more to it than that? Have a seat as I explain its immense power and what great works it can achieve. &lt;/p&gt;

&lt;p&gt;As always, I am here to break it down to a very digestible form.&lt;/p&gt;

&lt;p&gt;For the high performance of the reports we see, solid data models are vital. Designing a model correctly ensures fast calculation speed, accurate DAX data analysis, and easy report maintenance.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;u&gt;Data Schemas &lt;/u&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;schema&lt;/strong&gt; is the structural blueprint of your data model. It dictates how your data tables are organized and connected.&lt;br&gt;
Before deciding on a schema, you typically break your data into two types of tables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fact Tables&lt;/strong&gt;: The Actions (The Numbers)&lt;br&gt;
Think of a Fact Table as a continuous digital receipt log. It only cares about tracking business events and recording the raw numbers.&lt;br&gt;
&lt;em&gt;Example&lt;/em&gt; (Streaming App): Every time someone presses play on Netflix, it logs the event. It records Numeric Data like Duration_Minutes (45) and Pause_Count (2), alongside IDs to link to details.&lt;br&gt;
&lt;strong&gt;The Goal&lt;/strong&gt;: It answers "How much?" or "How many?"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dimension Tables&lt;/strong&gt;: The Context (The Text)A Dimension Table is your lookup list. It holds all the &lt;u&gt;descriptive details&lt;/u&gt; that give meaning to your raw numbers.&lt;br&gt;
&lt;em&gt;Example&lt;/em&gt; (Streaming App): Instead of repeating the movie title, director, release year, and genre on every single play receipt, you store it once in a &lt;code&gt;Movies&lt;/code&gt; lookup table next to a unique Movie_ID.&lt;br&gt;
&lt;strong&gt;The Goal&lt;/strong&gt;: It answers "Who?", "What?", or "Where?"&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Choosing your Blueprint(Schema)
&lt;/h3&gt;

&lt;p&gt;Now that you have known your Facts from your Dimensions, how do you arrange them in Power BI?&lt;br&gt;
There are 3 schema types. Namely:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Star&lt;/li&gt;
&lt;li&gt;Snowflake&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Star Schema
&lt;/h4&gt;

&lt;p&gt;The Star schema gets its name because of its shape. You place the number-heavy Fact Table in the center and surround it with your descriptive Dimension Tables like the points of a star.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why use it&lt;/strong&gt;: It provides the best query performance, reduces data redundancy, and uses one-to-many relationships that are easy for Power BI to process.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Snowflake Schema
&lt;/h4&gt;

&lt;p&gt;The Snowflake Schema happens when you split your dimension tables into even smaller lookup tables(e.g., a "Product" table branching out into separate "Brand" and "Category" tables).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why use it&lt;/strong&gt;: It is useful when you need to optimize storage or map highly complex hierarchical relationships, though it can slow down report rendering.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Flat Schema
&lt;/h4&gt;

&lt;p&gt;This represents a single, massive, consolidated table where all information lives together. This happens automatically when you load a single CSV or flat Excel file into Power BI.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why use it&lt;/strong&gt;: It requires no modeling effort and is perfectly fine for small, simple datasets. However, it leads to heavy data redundancy and poor performance on large datasets.
Here is a visual representation of the three.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffymq3if9ay2qx3ryxh2l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffymq3if9ay2qx3ryxh2l.png" alt="Visual rep of the 3 schemas" width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;u&gt;Relationships&lt;/u&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The 3 Core Settings of a Relationship&lt;/strong&gt;&lt;br&gt;
Every relationship you build in Power BI is defined by three main settings:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Cardinality (The Type of Connection)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;One-to-Many (1:*): The most common and efficient type. One row in your lookup table (e.g., Customers) connects to many rows in your transaction table (e.g., Sales).&lt;/li&gt;
&lt;li&gt;Many-to-One (*:1): The same as one-to-many, just viewed from the opposite direction.&lt;/li&gt;
&lt;li&gt;One-to-One (1:1): Links single unique rows between two tables. It is rarely used and usually means the tables should just be merged.&lt;/li&gt;
&lt;li&gt;Many-to-Many (&lt;em&gt;:&lt;/em&gt;): Links non-unique values on both sides. It should be avoided when possible because it can cause unpredictable calculations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. Cross Filter Direction (How the Data Flows)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Single Direction: The filter flows only one way—usually from the Dimension table down to the Fact table. This is the safest and fastest setting.&lt;/li&gt;
&lt;li&gt;Both Directions (Bi-directional): Filters flow both ways. While powerful, it can severely slow down your reports and create ambiguous data paths.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. Relationship Status
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Active: The primary path Power BI uses to calculate data between two tables. Only one active relationship can exist between any two tables at a time.&lt;/li&gt;
&lt;li&gt;Inactive: Secondary paths. They sit in the background and are only triggered when you specifically call them using DAX formulas (like USERELATIONSHIP).
&lt;em&gt;Active vs. Inactive Example&lt;/em&gt;
If your Sales table has a Order_Date and a Ship_Date, you can only link one of them actively to your Calendar table. You would make Order_Date active for your daily sales reports, and keep Ship_Date inactive, activating it only when calculating shipping backlogs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;u&gt;Power Query Joins: Merging Tables&lt;/u&gt;
&lt;/h3&gt;

&lt;p&gt;In Power BI, &lt;strong&gt;joins&lt;/strong&gt; are used to merge two tables permanently into a single, wider table during the data preparation phase. &lt;/p&gt;

&lt;p&gt;While &lt;em&gt;relationships&lt;/em&gt; connect separate tables in your visual model, &lt;em&gt;joins&lt;/em&gt; physically combine your data rows in the Power Query Editor using the &lt;strong&gt;Merge Queries&lt;/strong&gt; feature.&lt;/p&gt;

&lt;h4&gt;
  
  
  The 6 Types of Joins in Power BI
&lt;/h4&gt;

&lt;p&gt;Power BI offers six different ways to combine your datasets based on a matching column:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Left Outer:&lt;/strong&gt; Keeps &lt;strong&gt;all rows from the first table&lt;/strong&gt;, and only matching rows from the second table. This is the most common join.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Right Outer:&lt;/strong&gt; Keeps &lt;strong&gt;all rows from the second table&lt;/strong&gt;, and only matching rows from the first table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full Outer(The collector):&lt;/strong&gt; Keeps &lt;strong&gt;all rows from both tables&lt;/strong&gt;. Unmatched rows display null values for the missing data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inner(The matchmaker):&lt;/strong&gt; Keeps &lt;strong&gt;only rows that match&lt;/strong&gt; in both tables. Any unmatched data is completely discarded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Left Anti:&lt;/strong&gt; Keeps rows &lt;strong&gt;only present in the first table&lt;/strong&gt; that do not have a match in the second. It is perfect for finding missing records.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Right Anti:&lt;/strong&gt; Keeps rows &lt;strong&gt;only present in the second table&lt;/strong&gt; that do not have a match in the first.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Quick Comparison Matrix
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Join Type&lt;/th&gt;
&lt;th&gt;Records Kept from Table 1 (Left)&lt;/th&gt;
&lt;th&gt;Records Kept from Table 2 (Right)&lt;/th&gt;
&lt;th&gt;Best Used For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Left Outer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;Only Matches&lt;/td&gt;
&lt;td&gt;Adding descriptive columns to transactions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Right Outer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only Matches&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;Inverting data priorities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Full Outer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;Combining disparate budgets or targets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inner&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only Matches&lt;/td&gt;
&lt;td&gt;Only Matches&lt;/td&gt;
&lt;td&gt;Filtering for strict overlap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Left Anti&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only Unmatched&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Finding customers who &lt;em&gt;haven't&lt;/em&gt; bought yet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Right Anti&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Only Unmatched&lt;/td&gt;
&lt;td&gt;Finding orphaned data in secondary tables&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Join vs. Relationship: What's the difference?
&lt;/h3&gt;

&lt;p&gt;It is common to confuse Power Query joins with Data Model relationships. Here is how to differentiate them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Joins (Power Query):&lt;/strong&gt; Happen during data ingestion. They alter the physical structure of your data by flattening tables together, which consumes more memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relationships (Data Model):&lt;/strong&gt; Happen after the data is loaded. They keep tables separate and link them virtually, maximizing Power BI’s performance engine.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>analytics</category>
      <category>database</category>
      <category>dataengineering</category>
      <category>powerbi</category>
    </item>
    <item>
      <title>Into the Bashlands: Surviving the Big Black Screen Without an Undo Button</title>
      <dc:creator>Faith Njenga</dc:creator>
      <pubDate>Mon, 29 Jun 2026 21:44:39 +0000</pubDate>
      <link>https://dev.to/ms_njenga/head-on-with-linux-49c4</link>
      <guid>https://dev.to/ms_njenga/head-on-with-linux-49c4</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdbicnclzw3bcsgrru5ca.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdbicnclzw3bcsgrru5ca.jpeg" alt="LinuxCover" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;It's not talked about enough: the fear of the terminal window, or in other words, the big black screen.&lt;br&gt;
 Where there are no folder icons to double click on, their creation is not just a right-click, no buttons to undo mistakes and a single mistake can trigger an error message that looks like a loud, red alarm. Well, I want you to take a deep breath. The creeping of a sudden wave of imposter syndrome might not be news.&lt;br&gt;
 &lt;strong&gt;You are not alone in this&lt;/strong&gt;&lt;br&gt;
I decided to dive into the unknown and become a Data Engineer. If you do not know Linux in this line of Duty is a very crucial tool. Just like you I always thought that the command line was reserved for a certain category that I like call 'Big Boys' also known as cybersecurity experts or people who have memorized every shortcut since 1995. But over the last few weeks I have decided to get my hands dirty with real-world server deployment and yes, I can attest that: &lt;strong&gt;The terminal is not a monster. It is just a conversation.&lt;/strong&gt;&lt;br&gt;
Every time the terminal throws a scary Fatal error to you, it is not judging you but simply pointing out a missing configuration step in plain text. In this article, I am going to take my time and explain the nitty-gritty  of what I learned in setting up a remote cloud database from scratch. We will look at my exact real-world configuration, demystify database permissions and show how visual tools like Dbeaver can come to the rescue all these in simple and friendly terms.&lt;/p&gt;
&lt;h3&gt;
  
  
  Remote Access and Navigating
&lt;/h3&gt;

&lt;p&gt;Because a remote cloud server does not have a monitor or a keyboard attached to it in a physical room, we have to access its brain over the internet. The tool we use is &lt;strong&gt;SSH(Secure Shell)&lt;/strong&gt;. This of SSH as a secure, encrypted digital tunnel that stretches from your home laptop keyboard straight into the host operating system.&lt;br&gt;
For my recent project, our remote Ubuntu cloud server was hosted at the public IP address &lt;code&gt;159.65.222.96&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The login Banner&lt;/strong&gt;&lt;br&gt;
When you first connect via SSH using the administrative root user account, the server greets you with a system status banner:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9p2crmj50bif2n3dpews.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9p2crmj50bif2n3dpews.png" alt="connect via SSH to Ubuntu cloud server" width="800" height="249"&gt;&lt;/a&gt;&lt;br&gt;
Don't let this numbers overwhelm you. Look at them as a health dashboard for your remote computer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;usage of /: 4.2%&lt;/code&gt; means your server's storage drive is mostly empty. Your data pipelines have plenty of room to breathe.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Memory usage:28%&lt;/code&gt; tells you that more that two-thirds of your server's RAM is sitting open and ready to process heavy computational tasks.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Creating an Isolated User &amp;amp; The privilege shift
&lt;/h3&gt;

&lt;p&gt;To practice good security habits and protect our environment, we need to move away from the &lt;code&gt;root&lt;/code&gt; account. I created my own isolated user account (&lt;code&gt;faithn&lt;/code&gt;) using standard Linux configuration tools.&lt;br&gt;
Here is exactly how I built that user account and gave it administrative &lt;code&gt;sudo&lt;/code&gt; privileges while logged in as root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#1. Create the new user account (The system will prompt you to set a password)&lt;/span&gt;
root@assignmentServer:~# adduser faithn

&lt;span class="c"&gt;#2. Grant the new user access to administrative powers ('sudo' group)&lt;/span&gt;
root@assignmentServer:~# usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;faithn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Securely switch over to the new personal account by nesting a new connection&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4vnhuhgmc3h7sye03xrd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4vnhuhgmc3h7sye03xrd.png" alt="Logging in my isolated account" width="800" height="403"&gt;&lt;/a&gt;&lt;br&gt;
Look at that prompt change:&lt;br&gt;
'faithn@assignmentServer:~$'.The dollar sign($) means I am now standing safely inside my personal use sandbox. I have my own room, my own security, and I can't accidentally break the rest of the server.&lt;/p&gt;
&lt;h3&gt;
  
  
  Finding Your Way Around Without a Mouse
&lt;/h3&gt;

&lt;p&gt;Now that we are inside our isolated faithn user account, how do we look around? Because you cannot see any folders or icons, you have to use your keyboard as your eyes. Here are some commands that helped me navigate my new digital apartment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pwd&lt;/code&gt; (Print Working Directory): Tells you exactly where you are standing. The exact location where you are at.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fce43pfgiy0jry9ksbfkt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fce43pfgiy0jry9ksbfkt.png" alt="PWD" width="712" height="154"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ls -la&lt;/code&gt; (List All): This prints out every file and folder in your current directory, including hidden system files that control your settings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9st84kio8wk8lphzr1qo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9st84kio8wk8lphzr1qo.png" alt="list of files with details" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;mkdir&lt;/code&gt; (Make Directory)- This is equivalent of right-clicking on a desktop screen and selecting &lt;em&gt;New&amp;gt; Folder&lt;/em&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F09hx6i5gqwfse067npba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F09hx6i5gqwfse067npba.png" alt="Creating a folder" width="798" height="97"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;cd&lt;/code&gt; (Change Directory)- This is the physical act of walking into a folder.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3chtxt883d3xjtfpj8nl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3chtxt883d3xjtfpj8nl.png" alt="Navigating inside our new folder" width="800" height="104"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;touch&lt;/code&gt;- This instantly lays  blank sheets of paper on your desk. It is a fresh text file ready for configuration details or pipeline scripts. 
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj3evv2puk22s3je3l4bk.png" alt="Creating a new file" width="797" height="77"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Unmasking the PostgreSQL Prompt
&lt;/h2&gt;

&lt;p&gt;The next major conceptual hurdle for any beginner data engineer is understanding Context Switching.&lt;/p&gt;

&lt;p&gt;Once, I confirmed that our database software is installed by running &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1fpwrak4u4y4qfu1cpxd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1fpwrak4u4y4qfu1cpxd.png" alt="Get PostgreSQL version" width="800" height="79"&gt;&lt;/a&gt;&lt;br&gt;
It was time to log in.&lt;/p&gt;
&lt;h2&gt;
  
  
  The right way to Login In
&lt;/h2&gt;

&lt;p&gt;Once your user roles and permissions are properly set up the server, logging into your personal database should be clean and direct. You run this command into your regular Linux terminal prompt:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdyuicqn4eijqaafmjggh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdyuicqn4eijqaafmjggh.png" alt="Login to Postgresql" width="800" height="86"&gt;&lt;/a&gt;&lt;br&gt;
If everything is configured correctly, the server will bypass all administrative barriers and drop you straight into your destination. You will see a clean welcome message and responsive prompt ready for your data queries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;psql (16.14 (Ubuntu 16.14-0ubuntu0.24.04.1))
Type "help" for help.

&lt;/span&gt;&lt;span class="gp"&gt;faithn=#&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The First Trap: Getting Stuck in the Prompts
&lt;/h3&gt;

&lt;p&gt;However, when you are first figuring things out, it is incredibly easy to take a wrong turn and find yourself stuck like I was.&lt;br&gt;
 I tried to log straight into my database but I instead I fell directly into a classic terminal context trap that puzzles almost every single beginner:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgqta71ugnmh8g8zhnblr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgqta71ugnmh8g8zhnblr.png" alt="Basic trap" width="800" height="147"&gt;&lt;/a&gt;&lt;br&gt;
Let's dissect this line by line, because understanding this sequence will instantly remove your fear of database environments.&lt;/p&gt;
&lt;h3&gt;
  
  
  Decoding the Prompt Symbols ($, #, and -)
&lt;/h3&gt;

&lt;p&gt;The trailing symbols on your prompt lines are visual road signs showing which program is listening to your keyboard :&lt;br&gt;
&lt;code&gt;faithn@assignmentServer:~$&lt;/code&gt; The $ means you are in the Linux Shell. You run standard system commands here like ls or mkdir.&lt;br&gt;
&lt;code&gt;postgres=#&lt;/code&gt;The # means you crossed a portal into the PostgreSQL Engine. Linux commands will not work here; the server only accepts SQL code.&lt;br&gt;
&lt;code&gt;postgres-#&lt;/code&gt; The dash (-) means PostgreSQL is waiting for you to finish a SQL statement. Typing &lt;code&gt;psql&lt;/code&gt; twice triggers this because it isn't a valid SQL command, and the engine thinks you are still typing your sentence.&lt;br&gt;
&lt;strong&gt;The Fix&lt;/strong&gt;: If you ever get trapped on a line with a dash (-#) and your keyboard feels locked, press Ctrl + C. This breaks the waiting loop and returns you to a clean &lt;code&gt;postgres=#&lt;/code&gt; prompt.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Second Trap: The "Role Does Not Exist" Block
&lt;/h3&gt;

&lt;p&gt;Once you exit the prompt loops and confidently try to log into your database using your custom name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash/usr/lib/postgresql/16/bin/psql &lt;span class="nt"&gt;-d&lt;/span&gt; faithn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PostgreSQL flatly rejects you with a fatal message:&lt;br&gt;
&lt;code&gt;FATAL: role "faithn" does not exist&lt;/code&gt; &lt;br&gt;
This error makes your stomach drop. You think, "But wait, My Linux username is faithn, and I am typing it correctly! Why does it say I don't exist?"&lt;/p&gt;
&lt;h4&gt;
  
  
  Breaking Down the Trap
&lt;/h4&gt;

&lt;p&gt;This trap happens because Linux users and Database users are completely isolated from each other. Just because the server has a user profile named faithn doesn't mean the PostgreSQL application automatically knows who you are. PostgreSQL tracks its own separate guest list of users, which it calls Roles.&lt;br&gt;
Think of your Linux account as your security badge to get into the main university building. The Database Role is a completely separate guest list held by a second guard standing right outside the locked database room. When you first try to connect, that second guard checks his specific list, doesn't see your name, and locks you out,.&lt;br&gt;
 &lt;strong&gt;The Clean Solution&lt;/strong&gt;&lt;br&gt;
To fix this trap, we use the Master Database Admin identity (&lt;code&gt;postgres=#&lt;/code&gt;) to officially add your name to the database guest list and create your file storage container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;sql&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;ROLE&lt;/span&gt; &lt;span class="n"&gt;faithn&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;LOGIN&lt;/span&gt; &lt;span class="n"&gt;SUPERUSER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;faithn&lt;/span&gt; &lt;span class="k"&gt;OWNER&lt;/span&gt; &lt;span class="n"&gt;faithn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By explicitly running these, the two separate systems are perfectly linked. Now when you type &lt;code&gt;sudo -u postgres psql faithn&lt;/code&gt;, the database guard sees your name on the list and lets you right in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Schema and Importing Data with DBeaver
&lt;/h2&gt;

&lt;p&gt;Now that our database boundaries are unlocked, we can construct our ingestion environment. In data engineering, we use a Schema as a logical container to organize our tables. For this project, we are building a landing bucket called staging.&lt;br&gt;
We log into our database and run a simple, clean SQL script to lay down our structure:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzrb31c9vgnizzx4dfpwk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzrb31c9vgnizzx4dfpwk.png" alt="Creating a schema" width="799" height="190"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Bypassing Terminal Fatigue
&lt;/h3&gt;

&lt;p&gt;At this point, a classic beginner trap is trying to write massive INSERT INTO statements directly in the command line for dozens of records. It is a massive waste of time, and a single missing comma will break the entire thing. Real-world data engineers don't do everything the hard way, we balance terminal power with graphical comfort. This is the exact moment where DBeaver becomes your ultimate rescue tool. Because we configured our remote cloud server (159.65.222.96) to allow external network connections on port 5432, we can hook DBeaver directly into our backend using our personal faithn credentials. Instead of typing endless lines of code to force our data into the black box of the terminal, DBeaver peels back the scary layer of the command line and gives us a friendly, visual import wizard. I simply selected the mock student CSV spreadsheet generated on my local desktop, clicked through the visual mapping guide, and let the software automatically parse and load all records into our remote cloud database in seconds.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvsx1mj1c0lipzmg4sguj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvsx1mj1c0lipzmg4sguj.png" alt="Connectingdbeaver" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It gives you the absolute best of both worlds: your data is safely running on an enterprise Linux server in the cloud, but you get to interact with it using a beautiful, visual, human-friendly application.&lt;br&gt;
To verify that DBeaver successfully uploaded your records from your local PC to your remote cloud database, you can switch back to your Linux server terminal (&lt;code&gt;faithn@assignmentServer&lt;/code&gt;) and run this standard SQL query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;staging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What You Will See on Your Screen
&lt;/h3&gt;

&lt;p&gt;Running that command will print your data cleanly inside your terminal layout, showing you the exact rows you just uploaded through DBeaver:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;age |      course      | admission_number | grade | student_id |   gender   |    major    
-----+------------------+------------------+-------+------------+------------+-------------
  22 | Computer Science |      4083        | F     |        1   | Male       | Physics     
  22 | Business         |      7444        | F     |        2   | Female     | Physics     
  18 | Biology          |      4103        | C     |        3   | Female     | Physics     
  26 | Biology          |      7590        | B     |        4   | Female     | Chemistry   
  30 | Psychology       |      1978        | F     |        5   | Female     | Chemistry   
  30 | Biology          |      9396        | C     |        6   | Female     | English     
  24 | Biology          |      5989        | C     |        7   | Non-binary | Mathematics 
  25 | Biology          |      8362        | B     |        8   | Non-binary | Physics     
  25 | Business         |      3275        | D     |        9   | Non-binary | Chemistry   
  21 | Business         |      6182        | B     |       10   | Female     | Physics




&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>machinelearning</category>
      <category>linux</category>
      <category>database</category>
      <category>postgres</category>
    </item>
  </channel>
</rss>
