<?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: OSCAR MAINJE</title>
    <description>The latest articles on DEV Community by OSCAR MAINJE (@scarbyte).</description>
    <link>https://dev.to/scarbyte</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%2F3952253%2F84f134dd-05fc-49f4-bb7b-142d2be00305.jpg</url>
      <title>DEV Community: OSCAR MAINJE</title>
      <link>https://dev.to/scarbyte</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/scarbyte"/>
    <language>en</language>
    <item>
      <title>I Built a Digital Notebook for a Kiosk Owner Who's Tired of Paper Records — Here is What I Learned</title>
      <dc:creator>OSCAR MAINJE</dc:creator>
      <pubDate>Sun, 20 Sep 2026 11:22:54 +0000</pubDate>
      <link>https://dev.to/scarbyte/i-built-a-digital-notebook-for-a-kiosk-owner-whos-tired-of-paper-records-here-is-what-i-learned-29lo</link>
      <guid>https://dev.to/scarbyte/i-built-a-digital-notebook-for-a-kiosk-owner-whos-tired-of-paper-records-here-is-what-i-learned-29lo</guid>
      <description>&lt;h2&gt;
  
  
  The problem I set out to solve
&lt;/h2&gt;

&lt;p&gt;Picture a small kiosk in a town — the kind that sells bread, milk, sugar, eggs, tea leaves. The owner tracks everything in a notebook: what is in stock, what sold today, how much cash should be in the till. It works, until it doesn't, a page gets torn, a calculation gets missed, or nobody notices sugar is almost out until a customer asks for it.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Nuru Shop Sales Tracker&lt;/strong&gt;, a simple command-line tool in Python, to replace that notebook. No app download, no internet connection needed, no technical skill required beyond typing numbers into a menu.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it actually does
&lt;/h2&gt;

&lt;p&gt;When you run it, it asks for the kiosk's name and the owner's name, then enters a menu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. View Current Inventory Stock
2. Add or Restock a Product
3. Sell a Product
4. View Sales Report
5. Search Products
6. Save &amp;amp; Exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there, the owner can check what's in stock, add new products or top up existing ones, record a sale (with the system automatically calculating change to hand back in notes and coins), search for a product without needing to remember its exact name, and see a summary of the day's performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I'm most proud of: it thinks ahead for the owner
&lt;/h2&gt;

&lt;p&gt;The most useful part of this project isn't the menu — it's what happens quietly in the background. Every time the owner exits the program, two things happen automatically:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;strong&gt;restocking list&lt;/strong&gt; is generated for any product running low (fewer than 10 units), so the owner has a ready-made shopping list to hand their supplier, no manual stock-checking required.&lt;/li&gt;
&lt;li&gt;The full inventory and the day's sales are saved to files, so nothing is lost between sessions. The next time the program runs, it picks up exactly where it left off.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At the end of a shift, instead of doing the math, the owner instantly sees their total revenue and which product sold the most, the kind of insight that used to take flipping back through notebook pages to figure out.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I approached building it
&lt;/h2&gt;

&lt;p&gt;Rather than writing one giant block of code, I broke the problem into small, single-purpose functions. One to view stock, one to sell a product, one to generate the sales report, and so on and all are called from one main loop. This meant I could test each piece (does selling more than what's in stock actually get blocked? does a typo in the menu crash the program?) independently before trusting them to work together.&lt;/p&gt;

&lt;p&gt;I also spent some time on input validation. A shop owner using this tool might mistype a price, leave a field blank, or enter letters where numbers are expected, the program needed to handle all of that politely instead of crashing, since a crashed program is worse than a paper notebook.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd build next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A configurable low-stock threshold per product. 10 units is a sensible cutoff for something like bread, but not for a slower-moving item like sugar.&lt;/li&gt;
&lt;li&gt;Trend reporting across sessions, not just a single shift. Right now, sales history is saved but only ever summarized one day at a time.&lt;/li&gt;
&lt;li&gt;A CSV export, so an owner could hand their sales data to an accountant without needing to open a text file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What this project taught me
&lt;/h2&gt;

&lt;p&gt;The technical skills — dictionaries, file handling, input validation — were the easy part to learn. The harder, more useful skill was thinking about the &lt;em&gt;end user&lt;/em&gt; the whole way through: someone who isn't a programmer, might make typos, and just wants their day to run smoother than it did with a notebook. Every design decision, from the menu wording to the automatic restock alerts, came back to that person.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>From a Messy Spreadsheet to Business Insights: Analyzing a Hotel's Booking Data</title>
      <dc:creator>OSCAR MAINJE</dc:creator>
      <pubDate>Sat, 19 Sep 2026 12:21:16 +0000</pubDate>
      <link>https://dev.to/scarbyte/from-a-messy-spreadsheet-to-business-insights-analyzing-a-hotels-booking-data-7cd</link>
      <guid>https://dev.to/scarbyte/from-a-messy-spreadsheet-to-business-insights-analyzing-a-hotels-booking-data-7cd</guid>
      <description>&lt;p&gt;&lt;em&gt;How I cleaned 285 rows of real-world-style hotel data in PostgreSQL and turned it into revenue, occupancy, and guest-satisfaction insights in Power BI.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The brief
&lt;/h2&gt;

&lt;p&gt;Tembo Hotel &amp;amp; Suites is a mid-range business hotel in Nairobi that has been running since 2023. Like a lot of small hospitality businesses, its booking records are kept in a spreadsheet and the spreadsheet was a mess.&lt;/p&gt;

&lt;p&gt;The ask from the Hotel Director was simple to state and harder to deliver:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I need you to clean this data, load it into our new database, analyse it, and present your findings to the management team in two days. I want to know: which rooms make us the most money, which months are busiest, how our staff are performing, and whether our guests are happy. Make it look professional — use Power BI for the visuals."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the story of that pipeline: from a dirty CSV export to a 3-page Power BI report, and the business decisions the numbers actually point to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Staging everything as text
&lt;/h2&gt;

&lt;p&gt;The raw export had 285 rows and the kind of problems anyone who has cleaned real operational data will recognize: inconsistent capitalization, dates in two different formats mixed in the same column, currency values stored as strings like &lt;code&gt;KES 1,000&lt;/code&gt;, phone numbers with stray country codes and dashes, ratings outside the valid 1–5 range, and duplicate bookings.&lt;/p&gt;

&lt;p&gt;Loading data like this straight into a typed table is a losing game — a single erroneous row anywhere in the file kills the whole import. So the first step was a staging table where &lt;strong&gt;every column is &lt;code&gt;TEXT&lt;/code&gt;&lt;/strong&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;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;tembo_staging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;booking_id&lt;/span&gt;          &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;guest_name&lt;/span&gt;          &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;guest_phone&lt;/span&gt;         &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&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;This guarantees the load succeeds, and pushes all validation and type-casting downstream, where it can be handled using SQL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Audit before you touch anything
&lt;/h2&gt;

&lt;p&gt;Before writing a single &lt;code&gt;UPDATE&lt;/code&gt;, I ran a set of diagnostic &lt;code&gt;SELECT DISTINCT&lt;/code&gt; and pattern-matching queries to catalog exactly what was wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Casing inconsistencies in names and cities&lt;/li&gt;
&lt;li&gt;Non-standard category labels (&lt;code&gt;Dlx&lt;/code&gt; instead of &lt;code&gt;Deluxe&lt;/code&gt;, &lt;code&gt;MPESA&lt;/code&gt; and &lt;code&gt;M-PESA&lt;/code&gt; instead of one consistent label)&lt;/li&gt;
&lt;li&gt;Two date formats in the same column, distinguishable only by  checking whether the day or month value exceeded 12&lt;/li&gt;
&lt;li&gt;Currency symbols and commas embedded in numeric fields&lt;/li&gt;
&lt;li&gt;Guest ratings outside the valid 1–5 range&lt;/li&gt;
&lt;li&gt;Exact duplicate &lt;code&gt;booking_id&lt;/code&gt;s&lt;/li&gt;
&lt;li&gt;Negative values for &lt;code&gt;nights_stayed&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This audit-first approach matters for a simple reason: cleaning decisions should be based on what's actually in the data, not assumptions about what &lt;em&gt;might&lt;/em&gt; be wrong. It also means every subsequent &lt;code&gt;UPDATE&lt;/code&gt; targets a specific, confirmed problem — verified with a &lt;code&gt;SELECT&lt;/code&gt; first, per the golden rule of data cleaning:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Always run a &lt;code&gt;SELECT&lt;/code&gt; before an &lt;code&gt;UPDATE&lt;/code&gt; or &lt;code&gt;DELETE&lt;/code&gt;, so you know exactly which rows will change.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 3: Cleaning, one problem at a time
&lt;/h2&gt;

&lt;p&gt;With the audit complete, the fixes were mostly a mix of &lt;code&gt;TRIM&lt;/code&gt;, &lt;code&gt;INITCAP&lt;/code&gt;, &lt;code&gt;REGEXP_REPLACE&lt;/code&gt;, and targeted &lt;code&gt;CASE&lt;/code&gt; statements:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Text standardization:&lt;/strong&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;UPDATE&lt;/span&gt; &lt;span class="n"&gt;tembo_hotel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tembo_staging&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;guest_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;INITCAP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;TRIM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;guest_name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;guest_name&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;INITCAP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;TRIM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;guest_name&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Currency-as-text:&lt;/strong&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;UPDATE&lt;/span&gt; &lt;span class="n"&gt;tembo_hotel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tembo_staging&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;total_amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;NULLIF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'[^0-9]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'g'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;NUMERIC&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;total_amount&lt;/span&gt; &lt;span class="k"&gt;IS&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;AND&lt;/span&gt; &lt;span class="k"&gt;TRIM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Mixed date formats&lt;/strong&gt;, resolved by checking which part of the date exceeds 12 (and can therefore only be a day, not a month):&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;tembo_hotel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tembo_staging&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;check_in_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;CASE&lt;/span&gt;
        &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;split_part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;check_in_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/'&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="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;
            &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="n"&gt;TO_DATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;check_in_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'MM/DD/YYYY'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="n"&gt;TO_DATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;check_in_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'DD/MM/YYYY'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Phone numbers&lt;/strong&gt; with country codes normalized back to local format, and genuinely missing values set to &lt;code&gt;NULL&lt;/code&gt; rather than left as empty strings — an important distinction, since empty strings and nulls behave differently in aggregations and joins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Duplicates&lt;/strong&gt;, removed while keeping the first physical row for each &lt;code&gt;booking_id&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;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tembo_hotel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tembo_staging&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;ctid&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="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;MIN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctid&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;tembo_hotel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tembo_staging&lt;/span&gt;
    &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;booking_id&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After cleaning, 278 valid bookings remained from the original 285-row export.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Building the production layer
&lt;/h2&gt;

&lt;p&gt;Cleaned staging data moved into a clean &lt;code&gt;tembo_bookings&lt;/code&gt; table, and on top of that, a view — &lt;code&gt;vw_clean_bookings&lt;/code&gt; — that adds the derived fields Power BI needs for time intelligence and segmentation without recomputing them in DAX:&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;OR&lt;/span&gt; &lt;span class="k"&gt;REPLACE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="n"&gt;tembo_hotel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vw_clean_bookings&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="p"&gt;...,&lt;/span&gt;
    &lt;span class="k"&gt;EXTRACT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;YEAR&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;check_in_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;check_in_year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;TO_CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;check_in_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Month'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;check_in_month_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;CASE&lt;/span&gt;
        &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;guest_rating&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Satisfied'&lt;/span&gt;
        &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;guest_rating&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Neutral'&lt;/span&gt;
        &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;guest_rating&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Unsatisfied'&lt;/span&gt;
        &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="s1"&gt;'No rating'&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;satisfaction&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tembo_hotel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tembo_bookings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This view is the single source that the Power BI report connects to instead of raw tables scattered across the model.&lt;/p&gt;

&lt;p&gt;Indexes were added to match the query patterns the analysis would actually use: a composite index on &lt;code&gt;(check_in_date, booking_status)&lt;/code&gt; for time-based revenue filtering, &lt;code&gt;(room_type, booking_status)&lt;/code&gt; for occupancy and cancellation queries, &lt;code&gt;(staff_name, staff_department)&lt;/code&gt; for staff analysis, and a single-column index on &lt;code&gt;guest_city&lt;/code&gt; for location queries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: What the data actually says
&lt;/h2&gt;

&lt;p&gt;With the pipeline in place, here's what the numbers show.&lt;/p&gt;

&lt;h3&gt;
  
  
  Revenue is concentrated in the Suite, not the most-booked room
&lt;/h3&gt;

&lt;p&gt;Total confirmed revenue across 246 checked-out stays is &lt;strong&gt;KES 7,584,900&lt;/strong&gt;, averaging &lt;strong&gt;KES 30,833 per stay&lt;/strong&gt;. But the breakdown by room type tells an interesting story:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Room Type&lt;/th&gt;
&lt;th&gt;Bookings&lt;/th&gt;
&lt;th&gt;Revenue (KES)&lt;/th&gt;
&lt;th&gt;Avg. Nights&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;td&gt;94&lt;/td&gt;
&lt;td&gt;1,595,500&lt;/td&gt;
&lt;td&gt;2.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deluxe&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;2,165,700&lt;/td&gt;
&lt;td&gt;3.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Suite&lt;/td&gt;
&lt;td&gt;53&lt;/td&gt;
&lt;td&gt;2,596,100&lt;/td&gt;
&lt;td&gt;3.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Penthouse&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;1,227,600&lt;/td&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Standard is booked most often — it's the volume driver — but the &lt;strong&gt;Suite generates the most revenue&lt;/strong&gt; despite being booked far less frequently, thanks to its rate and the longest average stay of any room type. If the hotel wants to grow revenue rather than just occupancy, Suite is the room type worth protecting and promoting.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Penthouse has a serious cancellation problem
&lt;/h3&gt;

&lt;p&gt;This is the sharpest signal in the dataset. Cancellation and no-show rates by room type:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Room Type&lt;/th&gt;
&lt;th&gt;Cancellation Rate&lt;/th&gt;
&lt;th&gt;Revenue Lost (KES)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Suite&lt;/td&gt;
&lt;td&gt;3.6%&lt;/td&gt;
&lt;td&gt;120,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deluxe&lt;/td&gt;
&lt;td&gt;8.1%&lt;/td&gt;
&lt;td&gt;170,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;td&gt;15.3%&lt;/td&gt;
&lt;td&gt;320,300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Penthouse&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;24.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;565,000&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Penthouse — the hotel's second-highest-priced room — is cancelled or no-showed almost a quarter of the time. Those lost bookings alone account for &lt;strong&gt;nearly half of all lost revenue&lt;/strong&gt; (KES 1,175,300 total), from a room type that makes up just 9% of total bookings. This is the single highest-leverage fix available: a deposit or full prepayment policy plus a pre-arrival confirmation call for Penthouse bookings specifically would likely recover a meaningful chunk of that KES 565,000.&lt;/p&gt;

&lt;p&gt;Standard's 15.3% rate is lower per-booking, but because it's the highest-volume room type, the absolute loss (KES 320,300) is still worth addressing with the same approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  The most profitable room has the least satisfied guests
&lt;/h3&gt;

&lt;p&gt;Average guest rating by room type:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Room Type&lt;/th&gt;
&lt;th&gt;Avg. Rating&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Penthouse&lt;/td&gt;
&lt;td&gt;3.12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;td&gt;3.11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deluxe&lt;/td&gt;
&lt;td&gt;2.93&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Suite&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.83&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Suite guests are the least satisfied of any room type — worse than even the budget Standard rooms. Out of Suite guests who left a rating, 23 were unsatisfied against only 17 satisfied. This matters because Suite is also the top revenue earner: a guest paying the most is having the worst relative experience. Left unaddressed, this is a retention and reputation risk sitting directly on top of the hotel's most valuable segment. Overall, guest sentiment across the hotel is close to a coin flip — 41% satisfied vs. 38% unsatisfied — so this isn't a Suite-only issue, but it's most acute there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Guests barely use paid extras — and one service massively outperforms the rest
&lt;/h3&gt;

&lt;p&gt;66% of all bookings (185 of 278) included &lt;strong&gt;no extra service at all&lt;/strong&gt;. Of the services that were used, Conference Room bookings stand out sharply:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Times Used&lt;/th&gt;
&lt;th&gt;Total Revenue (KES)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Conference Room&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;195,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spa Treatment&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;45,500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Airport Pickup&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;32,500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Breakfast Buffet&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;16,800&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Laundry&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;10,400&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Room Service&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;7,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Swimming Pool&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;6,500&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Conference Room earns roughly 4x the next best-performing service from a similar number of bookings — unsurprising for a hotel positioned as a business hotel, but the low attach rate (13 bookings out of 278) suggests it's undersold rather than unwanted. Bundling it into corporate packages, rather than leaving it as an opt-in extra, is a low-effort revenue lever.&lt;/p&gt;

&lt;h3&gt;
  
  
  Revenue is growing, but volatile and heavily dependent on one city - Nairobi.
&lt;/h3&gt;

&lt;p&gt;Monthly revenue roughly doubled between late 2023 and 2024, though the dataset only starts in June 2023, so that first partial year isn't a fair year-over-year baseline — it likely reflects the hotel ramping up rather than a seasonal dip. Within 2024 alone, revenue swings 30–40% month to month with no single clean seasonal driver, though December and June are consistently the strongest months.&lt;/p&gt;

&lt;p&gt;On the guest side, &lt;strong&gt;45% of all bookings come from guests based in Nairobi&lt;/strong&gt;, with the next largest cities — Eldoret and Kisumu — each contributing roughly a fifth as much. This concentration is a natural byproduct of being a Nairobi-based business hotel, but it also means the guest base has limited geographic diversification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommendations for management
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Require a deposit or prepayment for Penthouse bookings&lt;/strong&gt; and a 48-hour pre-arrival confirmation call. This single change targets the largest revenue leak in the business.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Investigate the Suite guest experience&lt;/strong&gt; — review comments and staff feedback tied to Suite stays. A premium room underperforming on satisfaction is a compounding risk: it affects both repeat bookings and referrals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Package and actively market the Conference Room&lt;/strong&gt; to corporate guests, bundled with catering — it's already the highest-earning add-on per booking, just underused.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Introduce a simple post-stay follow-up&lt;/strong&gt; (SMS or email) that does two things at once: offers an add-on service and captures a guest rating. This addresses both the 66% no-extras rate and the 5% of stays with no rating recorded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extend the deposit/confirmation policy to Standard rooms&lt;/strong&gt; — with a lower cancellation rate than Penthouse, but high volume means the loss is still significant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make &lt;code&gt;guest_city&lt;/code&gt; a required field at intake&lt;/strong&gt; — 14 bookings (5%) currently have no recorded city, which limits the accuracy of any geographic analysis going forward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explore targeted outreach in Eldoret and Kisumu&lt;/strong&gt; before spreading marketing spend across many small feeder cities — they're already the next-largest segments after Nairobi.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What this project demonstrates
&lt;/h2&gt;

&lt;p&gt;Beyond the specific findings, this project is a fairly complete walkthrough of a real analytics workflow: staging dirty data safely, auditing before cleaning, applying targeted and verifiable fixes, building a clean semantic layer for BI tools to consume, and translating query results into decisions a non-technical audience — in this case, a Hotel Director.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you're working through a similar hotel/hospitality dataset or have questions about the cleaning approach, I'd love to hear from you in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>analytics</category>
      <category>learning</category>
      <category>visualization</category>
      <category>powerbi</category>
    </item>
    <item>
      <title>Building and Querying a Database: A Practical SQL Guide</title>
      <dc:creator>OSCAR MAINJE</dc:creator>
      <pubDate>Sat, 18 Jul 2026 14:35:20 +0000</pubDate>
      <link>https://dev.to/scarbyte/building-and-querying-a-database-a-practical-sql-guide-5fpn</link>
      <guid>https://dev.to/scarbyte/building-and-querying-a-database-a-practical-sql-guide-5fpn</guid>
      <description>&lt;p&gt;As a data analyst, mastering database design and querying is essential. In this article, I will walk you through how I built and queried a database schema for &lt;strong&gt;Greenwood Academy&lt;/strong&gt; using &lt;strong&gt;PostgreSQL&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;The article covers everything from defining or changing the structure of database objects using the Data Definition Language (&lt;strong&gt;DDL&lt;/strong&gt;), modifying data within tables using the Data Manipulation Language (&lt;strong&gt;DML&lt;/strong&gt;), and fetching and retrieving data from the database using the Data Query Language (&lt;strong&gt;DQL&lt;/strong&gt;). The article also explores filtering the results, utilizing specialized operators, and writing conditional logic with &lt;code&gt;CASE WHEN&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the Database (DDL)
&lt;/h3&gt;

&lt;p&gt;Data Definition Language (DDL) is used to define the database structure. For this task, I created a dedicated schema called &lt;code&gt;greenwood_academy&lt;/code&gt; to keep everything organized. Inside the schema, I created three tables: &lt;code&gt;students&lt;/code&gt;, &lt;code&gt;subjects&lt;/code&gt;, and &lt;code&gt;exam_results&lt;/code&gt;. Before creating the tables it is important to make sure that they are created in the intended schema. The &lt;code&gt;SET search_path TO [schema_name]&lt;/code&gt; is necessary for this. A better and safer practice is to always initialize your table names with the schema name, for example to create a table &lt;code&gt;students&lt;/code&gt; in the schema &lt;code&gt;greenwood_academy&lt;/code&gt; you can use the command &lt;code&gt;CREATE TABLE greenwood_academy.students&lt;/code&gt;. This will ensure that the table is created in the correct 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="c1"&gt;-- Creating a schema greenwood_academy and making sure SQL is using it.&lt;/span&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;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;span class="c1"&gt;-- Creating the students table.&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;greenwood_academy&lt;/span&gt;&lt;span class="p"&gt;.&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;h3&gt;
  
  
  Table Modifications
&lt;/h3&gt;

&lt;p&gt;In practice, database structural requirements change from time to time. In this case, I altered the existing table structures by adding a &lt;code&gt;phone_number&lt;/code&gt; column to the &lt;code&gt;students&lt;/code&gt; table, renamed a column in the &lt;code&gt;subjects&lt;/code&gt; table for better clarity i.e. &lt;code&gt;credits&lt;/code&gt; to &lt;code&gt;credit_hours&lt;/code&gt;, and then dropped the &lt;code&gt;phone_number&lt;/code&gt; column when it 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="c1"&gt;-- Adding a column 'phone_number'to the students table.&lt;/span&gt;

&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;greenwood_academy&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;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;span class="c1"&gt;-- Renaming column 'credits' to 'credit_hours'&lt;/span&gt;

&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt;   &lt;span class="n"&gt;greenwood_academy&lt;/span&gt;&lt;span class="p"&gt;.&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;span class="c1"&gt;-- Removing the phone_number column in the students table.&lt;/span&gt;

&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;greenwood_academy&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;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;h3&gt;
  
  
  Filling in the tables &amp;amp; Modifying the Database (DML)
&lt;/h3&gt;

&lt;p&gt;With the structures ready, Data Manipulation Language (DML) was used to modify the data within the tables. Data for 10 students, 10 subjects, and their respective exam records was inserted into the three tables.&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="c1"&gt;-- ===========================================================&lt;/span&gt;
&lt;span class="c1"&gt;-- Filling the Database(DML: INSERT, UPDATE, DELETE)&lt;/span&gt;
&lt;span class="c1"&gt;-- ===========================================================&lt;/span&gt;
&lt;span class="c1"&gt;-- Example of inserting student data&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;greenwood_academy&lt;/span&gt;&lt;span class="p"&gt;.&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;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="s1"&gt;'Brian'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Mutua'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'M'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2007-07-25'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Form 4'&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="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Cynthia'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Mutua'&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-11-05'&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;'Kisumu'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'David'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Kamau'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'M'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2007-02-18'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Form 4'&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="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Esther'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Akinyi'&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;'2009-06-30'&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;'Nakuru'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Note: Truncated for readability, full file includes 10 records per table&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After inserting the data into the tables, it is important to confirm that it is entered correctly before proceeding.&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="c1"&gt;-- SELECT query to confirm all 10 rows exist in each of the three tables&lt;/span&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;greenwood_academy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&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;greenwood_academy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subjects&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&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;greenwood_academy&lt;/span&gt;&lt;span class="p"&gt;.&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;h3&gt;
  
  
  Data Maintenance
&lt;/h3&gt;

&lt;p&gt;Databases are dynamic and get updates and deletions time and again. In this scenario, I updated a student's city, corrected a typing error in an exam mark, and deleted a specific exam result row entirely:&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="c1"&gt;-- UPDATE statement to change Esther Akinyi's city to Nairobi&lt;/span&gt;

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;greenwood_academy&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;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;span class="c1"&gt;-- UPDATE to fix the marks for result_id 5 to 59&lt;/span&gt;

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;greenwood_academy&lt;/span&gt;&lt;span class="p"&gt;.&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;span class="c1"&gt;-- DELETE statement to remove result_id 9 from the exam_results table&lt;/span&gt;

&lt;span class="k"&gt;DELETE&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt;  &lt;span class="n"&gt;greenwood_academy&lt;/span&gt;&lt;span class="p"&gt;.&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;&lt;strong&gt;Quick Reminder:&lt;/strong&gt; &lt;em&gt;Forgetting to specify the condition&lt;/em&gt; for the update or deletion &lt;em&gt;in the&lt;/em&gt; &lt;code&gt;WHERE&lt;/code&gt; &lt;em&gt;clause&lt;/em&gt; in each of the queries above &lt;em&gt;is catastrophic&lt;/em&gt;, as the command will affect the entire table.&lt;/p&gt;

&lt;h3&gt;
  
  
  Querying Data (Filtering with WHERE)
&lt;/h3&gt;

&lt;p&gt;Filtering data effectively reduces server load and isolates relevant insights. Below are a couple of specific queries using basic &lt;code&gt;WHERE&lt;/code&gt;, &lt;code&gt;AND&lt;/code&gt;, and &lt;code&gt;OR&lt;/code&gt; logical operators to look through the records:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Find all students in Form 3 AND from Nairobi:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&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;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="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;greenwood_academy&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;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="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;student_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Find all students who are in Form 2 OR Form 4:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&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;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="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;greenwood_academy&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;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="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;student_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Range, Membership &amp;amp; Search Operators
&lt;/h3&gt;

&lt;p&gt;To handle more versatile matching constraints, built-in SQL operators like &lt;code&gt;BETWEEN&lt;/code&gt;, &lt;code&gt;IN&lt;/code&gt;, and &lt;code&gt;LIKE&lt;/code&gt; are usually used.&lt;/p&gt;

&lt;h4&gt;
  
  
  Range Filtering (&lt;code&gt;BETWEEN&lt;/code&gt;)
&lt;/h4&gt;

&lt;p&gt;Useful for narrowing down continuous datasets like dates or numeric boundaries:&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="c1"&gt;-- Finding all exams that took place between 15th March 2024 and 18th March 2024.&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;result_id&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;subject_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exam_date&lt;/span&gt;  
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;greenwood_academy&lt;/span&gt;&lt;span class="p"&gt;.&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="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;exam_date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Set Membership (&lt;code&gt;IN&lt;/code&gt; / &lt;code&gt;NOT IN&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Replaces repetitive multi-line &lt;code&gt;OR&lt;/code&gt; statements:&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="c1"&gt;-- Finding all students who live in Nairobi, Mombasa, or Kisumu using IN&lt;/span&gt;

&lt;span class="k"&gt;SELECT&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="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;greenwood_academy&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;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;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Finding all students who are NOT in Form 2 or Form 3 using NOT IN.&lt;/span&gt;

&lt;span class="k"&gt;SELECT&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="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;greenwood_academy&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;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;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;student_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Pattern Matching (&lt;code&gt;LIKE&lt;/code&gt; with Wildcards)
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;%&lt;/code&gt; wildcard allows flexible string evaluation to search for prefixes or embedded substrings:&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="c1"&gt;-- Finding all students whose first name starts with the letter 'A' or 'E' using LIKE.&lt;/span&gt;

&lt;span class="k"&gt;SELECT&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="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;greenwood_academy&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;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="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;student_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Finding all subjects whose subject name contains the word 'Studies'.&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;subject_name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;greenwood_academy&lt;/span&gt;&lt;span class="p"&gt;.&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="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;subject_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Aggregating Data with COUNT
&lt;/h3&gt;

&lt;p&gt;Aggregation helps make sense of the larger scale of the data. Using the &lt;code&gt;COUNT()&lt;/code&gt; function, we can calculate quick statistical summaries, such as performance thresholds:&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="c1"&gt;-- Students currently in Form 3&lt;/span&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;AS&lt;/span&gt; &lt;span class="n"&gt;form_3_students&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;greenwood_academy&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;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;span class="c1"&gt;-- Exam results having a mark of 70 or above&lt;/span&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;AS&lt;/span&gt; &lt;span class="n"&gt;scores_70_and_above&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;greenwood_academy&lt;/span&gt;&lt;span class="p"&gt;.&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;h3&gt;
  
  
  Conditional Logic with CASE WHEN
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;CASE WHEN&lt;/code&gt; expression acts as an &lt;code&gt;if-else&lt;/code&gt; statement directly inside the SQL query. This is useful for dynamically creating computed category labels on without changing the underlying stored data.&lt;/p&gt;

&lt;h4&gt;
  
  
  Generating Performance Descriptions
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Exam results with a grade description&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;result_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;marks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;CASE&lt;/span&gt;
        &lt;span class="k"&gt;WHEN&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;80&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Distinction'&lt;/span&gt;
        &lt;span class="k"&gt;WHEN&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;60&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Merit'&lt;/span&gt;
        &lt;span class="k"&gt;WHEN&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;40&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Pass'&lt;/span&gt;
        &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="s1"&gt;'Fail'&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;perfomance&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;greenwood_academy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exam_results&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;marks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Grouping Students by Seniority Level
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Using CASE WHEN to label each student's level&lt;/span&gt;

&lt;span class="k"&gt;SELECT&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="k"&gt;CASE&lt;/span&gt;
        &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="k"&gt;class&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 3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Form 4'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Senior'&lt;/span&gt;
        &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="s1"&gt;'Junior'&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;student_level&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;greenwood_academy&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;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;student_level&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;This exercise simulates a realistic scenario for setting up and querying databases. It covers schema design, table modifications, and relevant classification using &lt;code&gt;CASE WHEN&lt;/code&gt;. The task gives foundational knowledge to manipulating enterprise-level data.&lt;/p&gt;

&lt;p&gt;The entire source code is structured cleanly into structured query files and tracked on my GitHub repository.&lt;/p&gt;

&lt;p&gt;Thanks for reading! If you have any questions or alternate methods for querying this data, feel free to drop a comment below! Happy querying!&lt;/p&gt;

</description>
      <category>sql</category>
      <category>database</category>
      <category>postgres</category>
      <category>learning</category>
    </item>
    <item>
      <title>The Ultimate Step-by-Step Guide: Connecting Power BI to Cloud-Based &amp; Local PostgreSQL</title>
      <dc:creator>OSCAR MAINJE</dc:creator>
      <pubDate>Sun, 05 Jul 2026 21:38:57 +0000</pubDate>
      <link>https://dev.to/scarbyte/the-ultimate-step-by-step-guide-connecting-power-bi-to-cloud-based-local-postgresql-3cdi</link>
      <guid>https://dev.to/scarbyte/the-ultimate-step-by-step-guide-connecting-power-bi-to-cloud-based-local-postgresql-3cdi</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Whether your data is securely stored in a file on your desktop or is being streamed from a cloud-based platform on Aiven, establishing a connection to Power BI is a fundamental skill for the modern data analyst. Connecting Power BI to a database shouldn't feel like guesswork. This article provides a comprehensive, step-by-step guide for linking Power BI Desktop to two distinct environments: a local PostgreSQL instance &lt;code&gt;localhost:5432&lt;/code&gt; and a cloud-hosted Aiven PostgreSQL deployment secured by an SSL &lt;code&gt;ca.pem&lt;/code&gt; Certificate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting Power BI Desktop to a Locally Hosted PostgreSQL Database
&lt;/h3&gt;

&lt;p&gt;Before opening Power BI, it's important to ensure that the local database is running and note the credentials. &lt;br&gt;
The credentials used should be as follows;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Host&lt;/strong&gt;: &lt;code&gt;localhost&lt;/code&gt; or &lt;code&gt;127.0.0.1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port&lt;/strong&gt;: &lt;code&gt;5432&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database Name&lt;/strong&gt;: The specific name of your database for example &lt;code&gt;postgres&lt;/code&gt; or your custom project database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Username&lt;/strong&gt;: Usually &lt;code&gt;postgres&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Password&lt;/strong&gt;: The password you created when installing PostgreSQL on your laptop&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Establishing the Connection in Power BI Desktop.
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Launch Power BI Desktop.&lt;/li&gt;
&lt;li&gt;On the &lt;strong&gt;Home&lt;/strong&gt; ribbon tab, click &lt;strong&gt;Get Data&lt;/strong&gt; &amp;gt; select &lt;strong&gt;More&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Database&lt;/strong&gt; from the left categories &amp;gt; click on &lt;strong&gt;PostgreSQL database&lt;/strong&gt; &amp;gt; click &lt;strong&gt;Connect&lt;/strong&gt;. As shown in the image below.&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%2Fmyi0u6atg2ccol5t6hy5.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%2Fmyi0u6atg2ccol5t6hy5.png" alt="Power BI - DB connection" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the connection window, fill out the database credentials as follows:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server&lt;/strong&gt;: Type &lt;strong&gt;Host:Port&lt;/strong&gt;, e.g., &lt;code&gt;127.0.0.1:5432&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database&lt;/strong&gt;: Type the name of your local database e.g., &lt;code&gt;postgres&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Connectivity Mode&lt;/strong&gt;: Select &lt;strong&gt;Import&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;OK&lt;/strong&gt; as shown below.&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%2F7r1w9djjiyhx8im4yn88.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%2F7r1w9djjiyhx8im4yn88.png" alt="Connection window" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Input your local database credentials
&lt;/h3&gt;

&lt;p&gt;A credential window will pop up asking how you want to access the database. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select the &lt;strong&gt;Database&lt;/strong&gt; tab on the left margin.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enter your local credentials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User name: Type &lt;code&gt;postgres&lt;/code&gt; (or your specific local username)&lt;/li&gt;
&lt;li&gt;Password: Type your local database password.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Connect&lt;/strong&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%2Fsybwbxagzpphftj3wwvs.png" alt="Local credentials" width="800" height="450"&gt;
Because local connections do not typically use an SSL certificate, Power BI might show a warning message saying: &lt;em&gt;The data source doesn't support an encrypted connection.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Simply click &lt;strong&gt;OK&lt;/strong&gt; or &lt;strong&gt;Run Unencrypted&lt;/strong&gt; to bypass this. 
&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%2Fuhloozs6779vgdii34ni.png" alt="Bypass" width="800" height="368"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since the data is residing on your own laptop, it does not travel across the internet, making an unencrypted local stream safe.&lt;/p&gt;

&lt;p&gt;A Navigator window will open showing all the schemas and tables inside your local database. You can now pick the dataset you wish and proceed to transform in Power Query.&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%2Folzehri0jn7z9f6xb7gj.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%2Folzehri0jn7z9f6xb7gj.png" alt="Data Import" width="800" height="265"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting Power BI Desktop to a Cloud Hosted PostgreSQL Database on Aiven.
&lt;/h3&gt;

&lt;p&gt;Power BI Desktop utilizes the underlying Windows Certificate Store to validate encrypted database links. Because Aiven uses its own to secure cloud data, Windows will block the connection as "Untrusted" unless we add it to the laptop's root directory.&lt;/p&gt;

&lt;p&gt;To do this, we must first download the CA certificate from the Aiven console.&lt;br&gt;
Open your web browser, navigate to your Aiven Console, and click on your running PostgreSQL service.&lt;br&gt;
Stay on the Overview page and scroll down to the Connection information section.&lt;br&gt;
Locate the row labeled CA Certificate and click the Download button next to it.&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%2F4q86sr4cd6ih1wwy2wvm.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%2F4q86sr4cd6ih1wwy2wvm.png" alt="CA Certificate" width="800" height="113"&gt;&lt;/a&gt;&lt;br&gt;
This will save a file named &lt;code&gt;ca.pem&lt;/code&gt; directly to the laptop's Downloads folder.&lt;/p&gt;

&lt;h4&gt;
  
  
  Install it into the Windows Trusted Root Authorities.
&lt;/h4&gt;

&lt;p&gt;To make this certificate trusted by Power BI for all connections, you must install it at the local machine.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the search box, search for &lt;strong&gt;"Manage user certificates&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In the left-hand folders console, expand &lt;strong&gt;Certificates&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Right-click&lt;/strong&gt; on the Trusted Root Certification Authorities folder &amp;gt; hover over &lt;strong&gt;All Tasks&lt;/strong&gt; &amp;gt; click &lt;strong&gt;Import&lt;/strong&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%2Fkfz7gt5bmzi4ji1r1sk6.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%2Fkfz7gt5bmzi4ji1r1sk6.png" alt="Import SSl Certificate" width="799" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Certificate Import Wizard will open.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Next → Browse&lt;/strong&gt; to find your file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crucial Step&lt;/strong&gt;: In the file browser pop-up, change the file extension filter dropdown in the bottom right to &lt;em&gt;All Files&lt;/em&gt;. Otherwise, your &lt;code&gt;ca.pem&lt;/code&gt; file will stay hidden.&lt;/li&gt;
&lt;li&gt;Navigate to your Downloads folder, select ca.pem, and click &lt;strong&gt;Open&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Ensure the option Place all certificates in the following store is selected and if it explicitly targets the Trusted Root Certification Authorities store.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Review the summary page and click &lt;strong&gt;Finish&lt;/strong&gt;. &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%2Fz820893hni6a9ju2xnxv.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%2Fz820893hni6a9ju2xnxv.png" alt="CA Certificate" width="800" height="767"&gt;&lt;/a&gt;&lt;br&gt;
A pop-up confirming "The import was successful" will appear.&lt;br&gt;
Close the console.&lt;/p&gt;

&lt;h4&gt;
  
  
  Establishing the Connection in Power BI Desktop
&lt;/h4&gt;

&lt;p&gt;Now that your laptop recognizes Aiven as a trusted authority, you can complete the link securely.&lt;br&gt;
Launch Power BI Desktop. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the top Home ribbon, click &lt;strong&gt;Get Data&lt;/strong&gt; → select &lt;strong&gt;More&lt;/strong&gt; → choose &lt;strong&gt;Database&lt;/strong&gt; → select &lt;strong&gt;PostgreSQL database&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Connect&lt;/strong&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%2F926l5c43mwzl41admt1j.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%2F926l5c43mwzl41admt1j.png" alt="Power BI - DB Connection" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Input your parameters copied from your Aiven Console:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server&lt;/strong&gt;: Enter your Host name followed by a colon and the port number (e.g.,&lt;code&gt;pg-123a4b5c-my-project.aivencloud.com:12345&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Database:Type  &lt;code&gt;defaultdb&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Data Connectivity Mode&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select &lt;strong&gt;Import&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;OK&lt;/strong&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%2F3uc0n0orlhzexjljnvib.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%2F3uc0n0orlhzexjljnvib.png" alt="Paremeters" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
When the database authentication window pops up, click the Database tab on the left-side margin.&lt;br&gt;
Input your database user details.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User name: &lt;code&gt;avnadmin&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Password: Paste your specific Aiven service password.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Connect&lt;/strong&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%2Fnadrzzgdci9rop7smw9j.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%2Fnadrzzgdci9rop7smw9j.png" alt="Connecting it All!" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A Navigator canvas window will appear displaying your database contents. &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%2Fgzu9e1wwsd1u5zuksg79.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%2Fgzu9e1wwsd1u5zuksg79.png" alt="Loading Data" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Simply check the box next to your loaded table (jcars in my case) and click &lt;strong&gt;Transform Data&lt;/strong&gt; to start transforming it within Power Query&lt;/p&gt;

&lt;h3&gt;
  
  
  In Conclusion ...
&lt;/h3&gt;

&lt;p&gt;At the end of the day, a data analyst's value isn't just in making pretty charts but in building robust, dependable data infrastructure. Moving your pipelines onto PostgreSQL and securing them via trusted CA root certificates proves you understand high-level data security and database operations.&lt;br&gt;
And that’s a wrap! You now have a fully functional, end-to-end data pipeline running seamlessly from a local environment or an encrypted cloud database straight into Power BI. No more connection timeouts, no more hidden SSL certificate rejections, and no more headaches. &lt;/p&gt;

</description>
      <category>postgres</category>
      <category>database</category>
      <category>analytics</category>
      <category>learning</category>
    </item>
    <item>
      <title>Power BI Data Modelling Demystified: Models, Schemas, Relationships, and Joins</title>
      <dc:creator>OSCAR MAINJE</dc:creator>
      <pubDate>Wed, 01 Jul 2026 12:31:04 +0000</pubDate>
      <link>https://dev.to/scarbyte/power-bi-data-modelling-demystified-models-schemas-relationships-and-joins-19bg</link>
      <guid>https://dev.to/scarbyte/power-bi-data-modelling-demystified-models-schemas-relationships-and-joins-19bg</guid>
      <description>&lt;h3&gt;
  
  
  Data Modelling in Power BI
&lt;/h3&gt;

&lt;p&gt;Assume you are running a business that requires you to order and supply different products from different suppliers and sell them to different customers every day. To keep records of your business, you are likely to use tools such as Excel to store data for your &lt;strong&gt;suppliers&lt;/strong&gt;, &lt;strong&gt;products&lt;/strong&gt;, &lt;strong&gt;customers&lt;/strong&gt;, and &lt;strong&gt;sales&lt;/strong&gt; made on a daily basis in a table. &lt;/p&gt;

&lt;p&gt;Having so much data in a table soon becomes problematic as the transactions grow into tens and hundreds of thousands. If this data is summarized in different tables, each storing data relating to one entity, then there's a need to establish the relationships between the different tables. This is where data modelling comes in. &lt;/p&gt;

&lt;p&gt;The purpose of data modeling in Power BI is to create a structured, optimized, and meaningful representation of data to support effective analysis, reporting, and visualization. Data modeling is a critical step in the Power BI workflow that transforms raw data into actionable insights for decision-making and business intelligence.&lt;/p&gt;

&lt;p&gt;A data model in Power BI is a logical representation of how data is structured and connected within the tool. It consists of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tables&lt;/strong&gt;: Represent the data from one or more sources like Excel files, CSVs, or cloud services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Relationships&lt;/strong&gt;: Define how these tables are connected to each other.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DAX (Data Analysis Expressions)&lt;/strong&gt;: The formula language used to create custom calculations, i.e., measures and calculated columns&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A well-designed data model is the foundation for creating reports and visualizations fast and should have the following features.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: Well-designed data models should handle more complex analysis as business needs grow without major changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced Maintenance&lt;/strong&gt;: Once the model is set up, it should be easier to maintain if it’s well organized and streamlined.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Proper Documentation&lt;/strong&gt;: Its design should ensure that anyone working with it can easily understand how it works.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why is Data Modeling Important in Power BI?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Efficient Data Exploration&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Data Modeling helps create hierarchies and drill-down paths, allowing users to easily explore data, uncover insights and identify trends.&lt;/p&gt;

&lt;p&gt;For example, hierarchy looks like this;&lt;br&gt;
In a Sales Data set: &lt;br&gt;
&lt;strong&gt;Country →County →City →Store →Product&lt;/strong&gt; &lt;br&gt;
or&lt;br&gt;
In a Time Data set: &lt;br&gt;
&lt;strong&gt;Year →Quarter →Month →Day&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Improved Performance&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A well-designed data model makes data retrieval fast and efficient, whereas a poorly structured data model with redundant data or complex relationships can slow down queries and delay reports.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Accurate Reporting&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having a good data model ensures accuracy, consistency, and reliability. This helps in generating reliable reports, provides better insights, and leads to better decision-making. Proper data modeling helps eliminate errors and ensures that the data used for analysis is correct and dependable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Types of Data Modeling
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Relational Model&lt;/strong&gt;: It prioritizes writing data efficiently without duplication. For example, a customer's address is only stored in one table, and linked to orders via IDs. This makes it great for applications but complex for analysts to run a simple report.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dimensional Model&lt;/strong&gt;: Uses Star or Snowflake schemas. It trades storage efficiency for query speed by duplicating and centralizing context (denormalization). For example, instead of querying multiple interconnected tables, an analyst looks at one central Sales Fact table linked to a Customer Dimension table to get sales by customer in seconds&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The table below shows comparison between the relational and dimensional data models.&lt;/em&gt;&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%2Fdftekwmpxj7lzebeqqm8.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%2Fdftekwmpxj7lzebeqqm8.png" alt="Comparison between a relational and dimensional data model" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Fact Tables and Dimension Tables
&lt;/h3&gt;

&lt;h4&gt;
  
  
  What is a Fact Table?
&lt;/h4&gt;

&lt;p&gt;A Fact table stores quantitative and numerical data which can be aggregated and analyzed. Fact table is a centerpiece of a data model and has information and has information about Transactions, Numerical measures like Sales amount, Quantity sold, Product cost and Foreign keys that links to dimension tables.&lt;/p&gt;

&lt;p&gt;In a Fact table, each row represents a single transaction or event, and each column represents a measurable attribute. For example, a sales fact table may have columns for the product sold, quantity and the total sales amount.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Characteristics:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Measures or Metrics:&lt;/strong&gt; Fact tables contain facts (quantitative data) such as sales amount, quantity sold, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Foreign Keys:&lt;/strong&gt; They have foreign keys that link to dimension tables, providing context for the facts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Granularity:&lt;/strong&gt; The level of detail or granularity of the fact table is defined during the design process (e.g., sales per day, per transaction).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
Consider a retail business analyzing its sales data. The fact table might look like this:&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%2Fyb6cju0ud08j31hzoa4s.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%2Fyb6cju0ud08j31hzoa4s.png" alt="Fact table" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ProductID, and StoreID are foreign keys linking to dimension tables.&lt;/p&gt;

&lt;h4&gt;
  
  
  What is a Dimension Table?
&lt;/h4&gt;

&lt;p&gt;A dimension table in Power BI contains descriptive data. It provides context and additional details to the numerical data in a fact table. For Example: A product dimension table may have columns such as product name, category, description and supplier name. Dimension tables usually contain fewer rows, whereas Fact tables can hold large amounts of data that grows over time.&lt;/p&gt;

&lt;p&gt;In a data model, a dimension table is connected to a fact table through a relationship. This allows Power BI users to analyze the fact table data by filtering, grouping and aggregating it based on the attributes in the dimension table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Characteristics:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Descriptive Data:&lt;/strong&gt; Contains descriptive data such as product names, customer names, dates, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Primary Keys:&lt;/strong&gt; Each dimension table has a primary key that corresponds to a foreign key in the fact table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attributes:&lt;/strong&gt; Dimension tables include various attributes that describe the dimension.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
Continuing with the retail business, dimension tables might look like this:&lt;br&gt;
Product Dimension Table&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%2Fislsh7rozhrtfeybzthv.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%2Fislsh7rozhrtfeybzthv.png" alt="Product Dimension Table" width="562" height="159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Store Dimension Table&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%2Fh2upcpm2vp08sjaatq4t.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%2Fh2upcpm2vp08sjaatq4t.png" alt="Store Dimension Table" width="571" height="159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In these examples:&lt;br&gt;
The &lt;strong&gt;Product Dimension Table&lt;/strong&gt; provides details about each product.&lt;br&gt;
The &lt;strong&gt;Store Dimension Table&lt;/strong&gt; provides details about each store.&lt;/p&gt;

&lt;p&gt;By linking these dimension tables to the fact table, you can generate insightful reports and analyses that provide a complete view of your business data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Schemas
&lt;/h3&gt;

&lt;h4&gt;
  
  
  What is a Schema?
&lt;/h4&gt;

&lt;p&gt;A schema is a collection of database objects, including tables, views, and indexes. It defines the structure of the data and the relationships between the different objects. In Power BI, a schema represents a logical grouping of tables that are related to each other.&lt;/p&gt;

&lt;h4&gt;
  
  
  Types of Schemas
&lt;/h4&gt;

&lt;p&gt;There are two types of schemas: Star schema and Snowflake schema. Let's explore each of these in detail.&lt;/p&gt;

&lt;h4&gt;
  
  
  Star schema
&lt;/h4&gt;

&lt;p&gt;Star Schema is a database design that separates data into fact tables(for summarizations) and dimension tables(for filtering and grouping).Its highly effective for Power BI as it optimizes the performance and usability by structuring data for easy reporting and visualization.&lt;/p&gt;

&lt;p&gt;Explicit Measures are custom calculations created with DAX Formulas, whereas Implicit Measures are automatically generated by Power BI from columns that can be summarized such as sum or average without needing custom formulas.&lt;/p&gt;

&lt;p&gt;A star schema may be preferable in some instances because it offers the following;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplified Querying:&lt;/strong&gt; Star Schemas are easy to understand and implement. Their denormalized structure reduces the number of joins and required to retrieve data. This simplifies and leads to faster data aggregation and reporting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Denormalization:&lt;/strong&gt; It is the process of combining tables to reduce complexity and improve performance often by adding redundant data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flexibility:&lt;/strong&gt; Star schemas are adaptable and easy to update when new data sources are added to a Power BI report.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Intuitive Analysis:&lt;/strong&gt; Star schemas provide more intuitive and user-friendly experience for end-users of a Power BI report. The data is organized in a logical and easy to understand manner, making it easier for end-users to identify trends and patterns in the data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Easier Maintenance:&lt;/strong&gt; Having fewer tables and simple relationships between them, star schemas are easier to maintain and update over time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;An example of a model with a star schema design is shown below.&lt;/em&gt;&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%2Fkanfyn73x9m8vh19ptge.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%2Fkanfyn73x9m8vh19ptge.png" alt="Star schema design" width="529" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Snowflake schema
&lt;/h4&gt;

&lt;p&gt;The Snowflake Schema is like the Star schema in terms of having a central fact table that everything passes through, but the main difference is that the Snowflake schema has normalized dimension tables as opposed to denormalized dimension tables for the Star schema.&lt;/p&gt;

&lt;p&gt;The Star schema typically goes down two levels of data hierarchy while the Snowflake schema goes to a third level. The purpose of a Snowflake schema is to normalize the denormalized data in a Star schema.&lt;/p&gt;

&lt;p&gt;In a snowflake schema, the relationships between tables form a pattern that resembles a snowflake, with the central fact table connected to multiple dimension tables and each dimension table potentially connected to additional sub-dimension tables.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;An example of a model with a snowflake schema design is shown below.&lt;/em&gt;&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%2F6o5phfsrsf3wpjaphf21.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%2F6o5phfsrsf3wpjaphf21.png" alt="Snowflake schema design" width="800" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Relationships in Power BI
&lt;/h3&gt;

&lt;p&gt;In Power BI, relationships between tables are created to enable data to be combined across them. This is done using the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Primary and Foreign Keys:&lt;/strong&gt; Ensures unique identifiers in fact tables match corresponding keys in dimension tables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cardinality:&lt;/strong&gt; Defines the type of relationship between two tables, defining how data and filters flow between them.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Relationships Concepts
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Primary keys&lt;/strong&gt;&lt;br&gt;
Primary keys are unique columns in a table that helps creates a relationship between two tables by sharing common values. The Primary key uniquely identifies each record.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Foreign keys&lt;/strong&gt;&lt;br&gt;
Foreign key is a column in one table whose values match the values of the primary key in another table.&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%2Flmywc4b49259t7ubne6h.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%2Flmywc4b49259t7ubne6h.png" alt="Fact table" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above image, In the product dimension table, primary key is the product Id column, which is a unique identifier of a product or row in the products table. The product dimension table is connected to the fact Orders Fact table based on Product ID, so here the product Id column within the orders table acts as a foreign key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cardinality&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each relationship in a model is defined by a cardinality type. It refers to the number of unique values in one table related to the number of unique values in another table.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;One to One (1:1)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This relationship occurs when one record in the first table is related to one and only one record in the second table. This is relatively uncommon in Power BI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One to Many(1:*)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This occurs when a single record in one table relates to multiple records in another table, commonly used to link dimension tables(one side)to fact tables(many side).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Many to One(*:1)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This occurs when multiple records in a fact table relate to a single record in a dimensional table, which is commonly used in Power BI because it simplifies data aggregation such as sum or average and enhances filtering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Many to Many (* : *)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This occurs when many records in the first table can be related to many records in the second table. This type of relationship is not directly supported in Power BI because it creates ambiguity in data aggregation and filtering, leading to performance issues and invalid results. Instead, such relationships require a bridge table to resolve the Many to Many connections.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ambiguity: Unclear data aggregation due to multiple relationship paths.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bridge Table: A table that links Many-to-Many relationships.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cross Filter Direction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Power BI, the cross-filter direction controls how filters propagate between visuals. Each relationship in a model defined with a cross-filter direction. It can be a single (Single directional) or both (Bi-directional).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A single arrowhead represents a single-direction filter in the direction of the arrowhead. Here, only one of the tables in the relationship can filter data across to the other table. This means filtering data in one table affects the data shown in the other table, but filtering in the other table does not affect the data shown in the first table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bi-Directional&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Bi-Directional cross-filtering enables them to apply filters on both sides of a table relationship(data can be filtered in either direction).This means filtering data in one table affects the data shown in the other table and vice versa. This type of filtering is less common and can degrade performance while potentially creating ambiguous filter paths. Cross-Filter options are dependent on the cardinality.&lt;/p&gt;

&lt;h4&gt;
  
  
  Active and Inactive Relationships
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Active Relationships&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Active Relationships are created in Power Bi Desktop’s Model View. To create one, drag and drop a common filed from one table to another table. Active relationships are visible in solid lines. These are default relationships used for filtering and calculations between tables ensuring data is linked for analysis.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inactive Relationships&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Power Bi, inactive relationships are used when multiple relationships exist between tables, letting us specify which one should be used for certain calculations. Marking a relationship as inactive prevents it from being used by default, resolving issues like ambiguous paths and conflicting filters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Joins
&lt;/h3&gt;

&lt;h4&gt;
  
  
  What are Joins?
&lt;/h4&gt;

&lt;p&gt;Table joins can be used to compare or combine rows between tables. They compare tables based on one or more related columns. When the compared row values between two tables are identical, they are considered a match. The behavior that follows depends on the join type. Mastering joins is a valuable skill for the data cleaning process.&lt;/p&gt;

&lt;h4&gt;
  
  
  How to Merge Queries
&lt;/h4&gt;

&lt;p&gt;So, how do you perform a join in Power Query? The easiest way to join tables in Power Query is by using merge queries. To start, go to the &lt;strong&gt;Home tab&lt;/strong&gt; in the ribbon and navigate to the &lt;strong&gt;Combine&lt;/strong&gt; section. There you will find the Merge Queries button. You have two options there:&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%2Fh4d67qb1ayg04qsf92p4.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%2Fh4d67qb1ayg04qsf92p4.png" alt="Merging Queries" width="787" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Merge Queries&lt;/strong&gt; performs a join on your current table and adds the result of this merge in the same query. This means you can easily see the impact of the merge in a single place.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Merge Queries as New&lt;/strong&gt; performs the same join on your table but puts the result of the merge in a separate query. The benefit of this approach is that your starting query remains the same. This means that you can still reference that starting query for other purposes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After choosing your desired way to merge queries, the below pop-up appears. This menu allows you to choose the Merge type you want to perform.&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%2Fm724p7jd2h9pmm290zyn.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%2Fm724p7jd2h9pmm290zyn.png" alt="Merging Queries" width="631" height="823"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Types of Joins
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Left Outer Join&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the most common joins is the Left Outer Join or simply the Left Join. The left outer join &lt;strong&gt;returns all rows from the Left Table (table1).&lt;/strong&gt; Then, by matching one or more column values with rows from table1 with similar column(s) from rows in table2, the join &lt;strong&gt;returns the matching values of the Right Table (table2).&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Right Outer Join&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Right Outer Join &lt;strong&gt;returns all values from the Right Table (Table2)&lt;/strong&gt; while only returning the &lt;strong&gt;matching values from the Left Table (Table1).&lt;/strong&gt;&lt;br&gt;
Its behavior is very similar to the Left Outer join, except that its base table is the Right table instead of the Left.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Full Outer Join&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are cases where you want to &lt;strong&gt;return all rows from both Table1 and Table2.&lt;/strong&gt; In those cases, the Full Outer Join is your friend.&lt;/p&gt;

&lt;p&gt;The Full Outer Join tries to match column values from Table1 with Table2 and if successful, puts them next to each other. The values of Table1 that don’t exist in Table2 get their own row. Any rows without a match in Table 2 return null values for these rows.&lt;/p&gt;

&lt;p&gt;Similarly, the values of Table2 that don’t exist in Table1 also get their own row. For these rows, the missing columns from Table1 get null values.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Left Anti Join&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Left Anti Join &lt;strong&gt;only returns rows from the Left Table&lt;/strong&gt; (Table1). Based on the key columns, the join searches for which values in Table1 do not exist in Table2. It then &lt;strong&gt;only returns the unique values from Table1.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Right Anti Join&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Right Anti-Join is the twin sister of the Left Anti-Join. It returns the rows from the Right Table (Table2) which are not present in the Left Table (Table1).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Inner Join&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Inner Join is a useful join that &lt;strong&gt;returns only those rows that have matching values in both the Left Table and the Right Table&lt;/strong&gt;. This can be useful when creating tables for your data model. Imagine filtering down a transaction table to contain only those transactions you want to analyze, but your product table still contains all products from your database.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Self Join&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A self-join is a join like all the others, but the table is joined with itself. In the Merge Queries interface, you can select the table to merge. When you want to do a self-join, you can simply fill in the same table twice.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The following images show the common types of joins in Power BI.&lt;/em&gt;&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%2Fkg111leyxd0hzf4vhmb4.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%2Fkg111leyxd0hzf4vhmb4.png" alt="Full Join &amp;amp; Union" width="625" height="193"&gt;&lt;/a&gt;&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%2F4p1qyk4rf95ipbzgwez4.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%2F4p1qyk4rf95ipbzgwez4.png" alt="Full Anti Join &amp;amp; Inner Join" width="618" height="201"&gt;&lt;/a&gt;&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%2F92idn6rljzblg3mknffc.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%2F92idn6rljzblg3mknffc.png" alt="Left Join &amp;amp; Right Join" width="607" height="181"&gt;&lt;/a&gt;&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%2Ftr364en28dx375zg1zme.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%2Ftr364en28dx375zg1zme.png" alt="Left Anti Join &amp;amp; Right Anti Join" width="604" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
This article has provided an overview of data modelling in Power BI by exploring the types of modelling, different types of schemas, the relationships that exist within a schema and how to join tables in Power Query, covering standard joins like Inner, Left, Right, and Full Outer. The article also explores special joins such as the Self Join, along with ways to union tables.&lt;/p&gt;

&lt;p&gt;It’s important to remember that each join type has its use case and that you should choose the one that best fits your needs. With these tools, you can now efficiently model data in Power BI.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Enjoy Power BI!&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>analytics</category>
      <category>beginners</category>
      <category>datascience</category>
      <category>learning</category>
    </item>
    <item>
      <title>How Excel is used in Real-World Data Analysis</title>
      <dc:creator>OSCAR MAINJE</dc:creator>
      <pubDate>Sat, 06 Jun 2026 12:03:10 +0000</pubDate>
      <link>https://dev.to/scarbyte/how-excel-is-used-in-real-world-data-analysis-2jjh</link>
      <guid>https://dev.to/scarbyte/how-excel-is-used-in-real-world-data-analysis-2jjh</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;What is Excel and who needs to know it?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Excel is a popular software that allows users to organize, format, and perform various calculations on data in a spreadsheet. Data in Excel is usually stored in &lt;strong&gt;rows or records&lt;/strong&gt; that run horizontally from left to right and &lt;strong&gt;columns or fields&lt;/strong&gt; that run vertically from top to bottom. The intersection of a row and column forms a &lt;strong&gt;cell&lt;/strong&gt; wherein data is entered.&lt;/p&gt;

&lt;p&gt;Excel is widely used in almost all industries to &lt;strong&gt;store, process, analyze, and visualize data&lt;/strong&gt;. In finance, sales, and project management, for instance, it’s used to track invoices and forecast revenue. It’s even more important for those in careers that work daily with data, such as data analysts and scientists, marketing managers and business owners, in their day-to-day work.&lt;/p&gt;

&lt;p&gt;What makes Excel even more popular are its collaboration tools like shared workbooks, which are valuable in business settings as they transform a single spreadsheet into dynamic and shared workspaces and improve operational efficiency.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Excel for Practical Data Analysis.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Having known what Excel is, we can now explore how it is used in real-world data analysis in 3 different industries and the most common features in Excel that facilitate that process.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Supply Chain and Logistics Management.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Managers in this industry can rely on Excel for inventory control to prevent product stockouts and track the shipping of products. In this case, &lt;strong&gt;conditional formatting&lt;/strong&gt; can be used to automatically highlight a product in a certain color if the current stock falls below the preset threshold. Functions such as &lt;code&gt;NETWORKDAYS()&lt;/code&gt; can be used to calculate the arrival dates for products on order.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Project Management.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Project managers can use Excel to make sure that complex projects are staffed adequately, executed within the budget, and delivered on time. Excel can be used to create a visual project timeline chart with fixed start and end dates. The function &lt;code&gt;SUMIF()&lt;/code&gt; can be used, for instance, to calculate the total time an employee has been assigned across multiple projects and prevent overburdening one individual.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Human Resources Management.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;HR managers can use Excel to manage employee data, analyze organizational costs, track overtime work, and use features such as &lt;strong&gt;PivotTables&lt;/strong&gt; to ensure employee salaries across various departments are correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Formulas and Functions in Excel.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Formulas and functions are used in Excel to analyze data and manipulate text. Although technically different, the two terms are often used interchangeably.&lt;br&gt;
&lt;strong&gt;Function&lt;/strong&gt;: A built-in tool that is pre-programmed, e.g., &lt;code&gt;SUM()&lt;/code&gt; or &lt;code&gt;COUNT()&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;Formula&lt;/strong&gt;: An equation written by the user to calculate a value in Excel. It always begins with an &lt;strong&gt;equal sign&lt;/strong&gt; (=), e.g., &lt;code&gt;=C4+B2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The following are the most common functions in Excel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Math and Trigonometry functions&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some functions in this category include the following;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SUM()&lt;/code&gt;: Adds its arguments.&lt;br&gt;
&lt;code&gt;SQRT()&lt;/code&gt;: Returns a positive square root.&lt;br&gt;
&lt;code&gt;ROUND()&lt;/code&gt;: Rounds a number to a specified number of digits.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The following image illustrates the use of the&lt;/em&gt; &lt;code&gt;ROUND()&lt;/code&gt; &lt;em&gt;function.&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.amazonaws.com%2Fuploads%2Farticles%2Fy4p3sv049s8f1zfcizms.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.amazonaws.com%2Fuploads%2Farticles%2Fy4p3sv049s8f1zfcizms.png" alt="Use of  raw `ROUND` endraw  function" width="793" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Text functions&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the functions used to extract, clean, format, and manipulate text data.&lt;br&gt;
Some functions in this category include the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;TRIM()&lt;/code&gt;: Removes spaces from text.&lt;br&gt;
&lt;code&gt;PROPER()&lt;/code&gt;: Capitalizes the first letter in each word of a text    value&lt;br&gt;
&lt;code&gt;UPPER()&lt;/code&gt;: Converts text to uppercase&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The following image shows the use of the&lt;/em&gt; &lt;code&gt;UPPER()&lt;/code&gt; &lt;em&gt;function&lt;/em&gt;&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.amazonaws.com%2Fuploads%2Farticles%2Ffl5383f49ov3kbsufukk.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.amazonaws.com%2Fuploads%2Farticles%2Ffl5383f49ov3kbsufukk.png" alt=" raw `UPPER` endraw  function in Excel" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Statistical functions&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These functions are used to summarize, analyze and interpret data.&lt;br&gt;
Some functions in this category include the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MIN()&lt;/code&gt;Returns the minimum value in a list of arguments&lt;br&gt;
&lt;code&gt;COUNT()&lt;/code&gt; Counts how many numbers are in the list of arguments&lt;br&gt;
&lt;code&gt;AVERAGEIF()&lt;/code&gt; Returns the average of all the cells in a range that meet a given criteria&lt;br&gt;
&lt;code&gt;AVERAGE()&lt;/code&gt; Returns the average of its arguments&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The following image shows the use of the&lt;/em&gt; &lt;code&gt;AVERAGE()&lt;/code&gt; &lt;em&gt;function to calculate the average current price of 10 products&lt;/em&gt;&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.amazonaws.com%2Fuploads%2Farticles%2Fdrnqmchgr9glofjnzu5q.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.amazonaws.com%2Fuploads%2Farticles%2Fdrnqmchgr9glofjnzu5q.png" alt="Use of the  raw `AVERAGE()` endraw  function" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Having embarked on a journey of learning Excel as a tool for data analysis, I no longer see data just as a collection of numbers and texts with little meaning in real life. If analyzed well using tools such as Excel, data proves to have power to answer important questions and solve many operational challenges that businesses face from day to day. As I continue to develop my skills in Data Science, Analytics and AI, I now appreciate that even though there are more advanced tools like Python and Power BI, Excel will remain to be a tool that is widely used in the data field.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>data</category>
      <category>analytics</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
