Sqlism
Loading…
Learning path

Become an Analytics Engineer with SQL

Analytics engineers sit between the data engineer who lands the raw data and the analyst who asks the questions. Your job is to turn messy source tables into clean, tested, documented models that everyone can trust, and nearly all of it is written in SQL.

8 Modules
~7 hrs, self-paced
3 Portfolio Projects
0 of 8 modules complete

This path follows how a modern analytics team actually builds a warehouse: readable modular SQL, a clean staging layer, star-schema marts, history with slowly changing dimensions, incremental loads that don't rebuild everything nightly, and the testing, version control and documentation habits that make your models trustworthy. Tools like dbt package these ideas, but every one of them is plain SQL underneath, so you can practice them all on Sqlism.

  1. 1

    Modular SQL with CTEs

    30 min

    Analytics engineering starts with SQL other people can read. Instead of one 300-line query, break the logic into named steps with WITH: import the sources, transform them, then produce the final select. Each step has one job, so a reviewer can follow it top to bottom.

    WITH orders AS (
        SELECT * FROM stg_orders
    ),
    customers AS (
        SELECT * FROM stg_customers
    ),
    customer_orders AS (
        SELECT customer_id, COUNT(*) AS order_count, SUM(amount) AS lifetime_value
        FROM orders
        GROUP BY customer_id
    )
    SELECT c.customer_id, c.customer_name,
           COALESCE(co.order_count, 0) AS order_count,
           COALESCE(co.lifetime_value, 0) AS lifetime_value
    FROM customers c
    LEFT JOIN customer_orders co ON co.customer_id = c.customer_id;
    Name CTEs after what they contain (customer_orders), not how they were built (cte2). Six months later the name is the only documentation anyone reads.
  2. 2

    Staging Layer: Rename, Cast, Clean

    30 min

    The staging layer is a thin, one-to-one view over each raw source table. It renames cryptic columns, casts types, standardizes casing and NULLs, and nothing more: no joins, no business logic. Every model downstream reads from staging, never from raw tables directly.

    CREATE VIEW stg_customers AS
    SELECT
        CAST(cust_no AS INTEGER)            AS customer_id,
        TRIM(cust_nm)                       AS customer_name,
        LOWER(NULLIF(TRIM(email_addr), '')) AS email,
        UPPER(NULLIF(country_cd, 'N/A'))    AS country_code,
        CAST(created_ts AS TIMESTAMP)       AS created_at
    FROM raw_crm_customers;
    If a source system renames a column, a good staging layer means you fix it in exactly one place instead of in every model that uses it.
  3. 3

    Dimensional Modeling: Facts & Dimensions

    40 min

    Marts are the tables analysts and BI tools query. Model them as a star schema: fact tables of business events at a clearly stated grain, surrounded by dimension tables of descriptive attributes. Decide the grain first ("one row per order line") and every other design choice gets easier.

    CREATE TABLE fct_order_lines AS
    SELECT
        ol.order_line_id,              -- grain: one row per order line
        o.order_date,
        o.customer_id,
        ol.product_id,
        ol.quantity,
        ol.quantity * ol.unit_price AS gross_amount
    FROM stg_order_lines ol
    JOIN stg_orders o ON o.order_id = ol.order_id;
    Write the grain as a comment at the top of every fact table. Most "wrong total" bugs come from joining two tables that silently have different grains.
  4. 4

    Tracking History with Snapshots & SCD Type 2

    35 min

    Dimensions change: customers move, products get re-categorized. A snapshot (SCD Type 2) keeps every version of a row with valid_from / valid_to dates, so last year's report still shows last year's truth. Facts then join on the business key and the date range.

    SELECT f.order_line_id, f.order_date, d.region
    FROM fct_order_lines f
    JOIN dim_customer_history d
      ON d.customer_id = f.customer_id
     AND f.order_date BETWEEN d.valid_from AND d.valid_to;
    Only track history for attributes the business actually reports on over time. Snapshotting every column of every table creates huge, slow dimensions nobody needs.
  5. 5

    Incremental Models & Upserts

    35 min

    Rebuilding a billion-row fact table every night is slow and expensive. An incremental model only processes rows that arrived or changed since the last run, using a watermark such as updated_at, and merges them into the existing table with an upsert so re-runs never create duplicates.

    MERGE INTO fct_orders t
    USING (
        SELECT * FROM stg_orders
        WHERE updated_at > (SELECT MAX(updated_at) FROM fct_orders)
    ) s
    ON t.order_id = s.order_id
    WHEN MATCHED THEN UPDATE SET status = s.status, amount = s.amount, updated_at = s.updated_at
    WHEN NOT MATCHED THEN INSERT (order_id, status, amount, updated_at)
                          VALUES (s.order_id, s.status, s.amount, s.updated_at);
    Every incremental model needs a documented way to do a full refresh. Logic changes, late-arriving data and bugs all eventually require rebuilding from scratch.
  6. 6

    Data Tests: Unique, Not Null, Relationships

    30 min

    A model isn't done until it's tested. The core tests are simple SQL queries that return the rows breaking a rule, and a test passes when it returns nothing: primary keys are unique and not null, foreign keys point at real dimension rows, and categorical columns only contain accepted values.

    -- Relationship test: every order must belong to a known customer
    SELECT f.order_id, f.customer_id
    FROM fct_orders f
    LEFT JOIN dim_customers d ON d.customer_id = f.customer_id
    WHERE d.customer_id IS NULL;   -- zero rows = pass
    Add a test every time you fix a data bug. The bug that already happened once is the one most likely to happen again.
  7. 7

    Version Control & CI/CD for SQL

    30 min

    Analytics engineers work like software engineers: every model change goes through Git, a pull request and code review. A CI pipeline builds only the changed models in an isolated schema and runs their tests before anything can merge, so broken SQL never reaches the dashboards people rely on.

    Build once and promote the same code from Dev to Test to Prod. Environment differences (database names, warehouse sizes) belong in configuration, not in the SQL.
  8. 8

    Documentation, Lineage & Metric Definitions

    25 min

    A model nobody understands won't be trusted. Document each model's purpose and grain, describe its columns, and keep lineage visible so you can answer "if I change this source, which dashboards break?". Define key metrics (revenue, active customer) once, centrally, instead of letting every report invent its own version.

    When two dashboards show different "revenue", the fix is rarely the SQL; it's agreeing on one definition and building it once in a shared model.

Practice on real projects

These projects use the modeling, testing and pipeline patterns from this path end to end.

Get interview-ready

Analytics engineering interviews mix SQL fluency with modeling judgement: expect window functions, "model this business process" whiteboard questions, and how you would test it.

Validate what you've learned

25 questions covering everything above. Score 80% or higher to earn your Analytics Engineer badge on your dashboard.

Upgrade to Sqlism Pro to take the validation quiz

25 questions · pass at 80%+ to earn your Analytics Engineer badge on your dashboard. One-time payment, lifetime access.

Get Sqlism Pro