Skip to content
Aabha AI Academy
Skip to reading

SQL

Build Guide

from pathlib import Path
import json,sys,re,html
import markdown
R=Path(__file__).resolve().parent.parent;mods=json.loads((R/'validation/module_map.json').read_text())
CSS='''
:root{--ink:#142f40;--muted:#496273;--line:#d8e1e6;--blue:#0b5970;--paper:#fff;--soft:#f2f6f8;--green:#0b6b4e}
*{box-sizing:border-box}html{scroll-behavior:smooth;scroll-padding-top:22px}body{margin:0;color:var(--ink);background:#f5f7f9;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;font-size:17px;line-height:1.75}a{color:var(--blue);text-underline-offset:3px}a:hover{color:var(--green)}a:focus-visible,summary:focus-visible{outline:3px solid #d97706;outline-offset:4px}.skip{position:absolute;top:-80px;left:20px;background:white;padding:12px;z-index:5}.skip:focus{top:12px}.hero{background:#113545;color:white;padding:54px max(24px,calc((100% - 1120px)/2));border-bottom:6px solid #4eb79c}.hero p{max-width:760px;color:#e0ecf1;margin:12px 0}.eyebrow{font-weight:650;letter-spacing:.12em;font-size:13px;text-transform:uppercase}.hero h1{font-size:clamp(30px,4vw,50px);line-height:1.12;max-width:850px;margin:17px 0}.hero a{color:#dbfff1}.layout{max-width:1180px;margin:0 auto;padding:32px 22px 70px;display:grid;grid-template-columns:230px minmax(0,1fr);gap:32px}nav{font-size:14px;line-height:1.5;align-self:start;position:sticky;top:20px;max-height:95vh;overflow:auto;padding-right:8px}nav a{display:block;padding:7px 8px;border-bottom:1px solid var(--line);text-decoration:none}nav strong{display:block;margin:20px 8px 8px}nav details summary{font-weight:700;padding:8px;cursor:pointer}main{min-width:0}section{background:white;padding:36px 42px;margin-bottom:24px;border:1px solid var(--line);border-radius:12px;overflow:hidden}h1,h2,h3,h4{line-height:1.25;color:#102c3d;font-weight:750;scroll-margin-top:25px}main h1{font-size:32px;margin:0 0 24px}h2{font-size:25px;margin:38px 0 15px}h3{font-size:20px;margin:30px 0 12px}p{margin:14px 0 20px}li{margin:6px 0}pre{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;background:#edf3f6;border:1px solid #d5e0e6;padding:19px 20px;overflow-x:auto;font-size:13.5px;line-height:1.65;border-radius:6px;tab-size:2}code{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:.86em;overflow-wrap:anywhere}pre code{font-size:inherit;overflow-wrap:normal}img{display:block;width:100%;height:auto;margin:25px auto;border:1px solid var(--line);border-radius:7px}.table-wrap{overflow:auto;margin:24px 0;max-width:100%}table{border-collapse:collapse;width:100%;font-size:14px;line-height:1.55}th,td{border:1px solid #ccd8e0;text-align:left;padding:10px 12px;vertical-align:top}th{background:#e8f0f4;font-weight:700}tr:nth-child(even){background:#f8fafb}.meta{font-size:14px;color:var(--muted)}.jump{display:flex;gap:15px;flex-wrap:wrap;font-size:14px;border-top:1px solid var(--line);padding-top:18px;margin-top:32px}.tag{color:var(--green);font-weight:650;font-size:13px;letter-spacing:.04em;text-transform:uppercase}footer{max-width:1120px;margin:0 auto;padding:0 24px 45px;font-size:14px;color:var(--muted)}
@media(max-width:900px){.layout{grid-template-columns:1fr;gap:20px;padding:20px 14px}nav{position:static;max-height:none;background:#fff;border:1px solid var(--line);border-radius:10px;padding:10px}nav details:not([open]) a{display:none}section{padding:26px 23px}main h1{font-size:27px}.hero{padding:34px 23px}.hero h1{font-size:35px}}
@media(max-width:480px){body{font-size:16px;line-height:1.7}section{padding:24px 18px;border-radius:8px}main h1{font-size:26px}h2{font-size:23px}pre{font-size:12.5px;padding:14px}table{font-size:13px;min-width:480px}.hero h1{font-size:32px}}
@media print{body{background:white;color:black;font-size:11pt}.hero{background:white;color:black;padding:0 0 20px;border-bottom:1px solid #999}.hero p,.hero a{color:black}.layout{display:block;padding:0}nav,.skip,.jump{display:none}section{padding:0;border:0;page-break-before:always}section:first-child{page-break-before:auto}pre{white-space:pre-wrap;overflow-wrap:anywhere;font-size:8pt}h1,h2,h3{break-after:avoid}img{break-inside:avoid}th{background:#eee}a{color:black}table{font-size:9pt}.table-wrap{overflow:visible}}
'''
(R/'style.css').write_text(CSS)
def render(md):
 s=markdown.markdown(md.replace('../visuals/','visuals/'),extensions=['tables','fenced_code','toc'])
 s=s.replace('<table>','<div class="table-wrap"><table>').replace('</table>','</table></div>')
 s=re.sub(r'<code>((?:sql|validation)/[^< ]+\.(?:sql|csv|json))</code>',r'<a href="\1"><code>\1</code></a>',s)
 return s
nav='<a href="#syllabus">Syllabus and outcomes</a><a href="#setup">Set up your lab</a><a href="#dictionary">Data and metric definitions</a><strong>Ordered modules</strong>'
nav+=''.join(f'<a href="#module-{m["module"]:02d}">{m["module"]:02d} {html.escape(m["title"])}</a>' for m in mods)
nav+='<strong>Finish and review</strong><a href="#assessment">Capstone assessment</a><a href="solutions.html">Separate exercise solutions</a><a href="#validation">Validation and limits</a><a href="#sources">References</a>'
sections=[]
for id,file in [('syllabus','SYLLABUS.md'),('setup','SETUP.md'),('dictionary','DATA_DICTIONARY.md')]:sections.append(f'<section id="{id}">{render((R/file).read_text())}</section>')
for m in mods:
 n=m['module'];sections.append(f'<section id="module-{n:02d}"><p class="tag">Module {n} of 13</p>'+render((R/m['lesson_file']).read_text())+f'<div class="jump"><a href="#syllabus">Back to syllabus</a><a href="solutions.html#exercise-{n:02d}a">Answers after your attempt</a>'+ (f'<a href="#module-{n+1:02d}">Next module</a>' if n<13 else '<a href="#assessment">Assessment rubric</a>')+'</div></section>')
for id,file in [('assessment','ASSESSMENT.md'),('validation','VALIDATION.md'),('sources','SOURCES.md')]:
 if (R/file).exists():sections.append(f'<section id="{id}">{render((R/file).read_text())}</section>')
header='<header class="hero"><div class="eyebrow">Aabha AI Academy • PostgreSQL edition</div><h1>SQL for Data Analysis and AI</h1><p>Build a query you can explain, a result you can verify, and an AI feature table with an honest time boundary.</p><p>13 ordered modules · Synthetic retail lab · No paid signup required</p><p><a href="#syllabus">Start with the syllabus</a> · <a href="solutions.html">Separate solutions</a></p></header>'
page='<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>SQL for Data Analysis and AI | Aabha AI Academy</title><link rel="stylesheet" href="style.css"></head><body><a class="skip" href="#main">Skip to course content</a>'+header+'<div class="layout"><nav aria-label="Course navigation"><details open><summary>Course map</summary>'+nav+'</details></nav><main id="main">'+''.join(sections)+'</main></div><footer>Course package 2026-10-14.1. Synthetic practice only. The offline guide is a reading companion; SQL runs through the separate local practice setup.</footer></body></html>'
(R/'index.html').write_text(page)
answers='<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>SQL course solutions | Aabha AI Academy</title><link rel="stylesheet" href="style.css"></head><body><a class="skip" href="#main">Skip to answers</a><header class="hero"><div class="eyebrow">Aabha AI Academy • Separate answer key</div><h1>SQL exercise solutions</h1><p>Attempt the exercises first, then compare the method, result and reasoning.</p><a href="index.html">Return to the course</a></header><div class="layout"><nav aria-label="Solution navigation"><a href="index.html">Course and syllabus</a>'+''.join(f'<a href="#exercise-{n:02d}a">Module {n:02d} answers</a>' for n in range(1,14))+'</nav><main id="main"><section>'+render((R/'SOLUTIONS.md').read_text())+'</section></main></div></body></html>'
(R/'solutions.html').write_text(answers)
# Root coursebook uses root-relative image files; lesson files use ../visuals.
p=R/'COURSEBOOK.md';p.write_text('# SQL for Data Analysis and AI\n\nAabha AI Academy • Beginner to foundational • PostgreSQL edition\n\nRead SYLLABUS.md and SETUP.md first. This coursebook contains the ordered teaching narrative and worked examples. Independent answers are in a separate document.\n\n'+'\n\n'.join((R/m['lesson_file']).read_text().replace('../visuals/','visuals/') for m in mods))

Download this source file