🔒 Guided

Pre-launch preview. Authorised access only.

Incorrect code

Guided by A Guide to Cloud
Explore AB-900 AI-901
Guided DP-800 Domain 1
Domain 1 — Module 6 of 10 60%
6 of 28 overall

DP-800 Study Guide

Domain 1: Design and Develop Database Solutions

  • Table Design: Columns, Types, and Indexes Free
  • Constraints: Protecting Your Data Free
  • Specialised Tables and Graph Queries Free
  • JSON in SQL: Store, Query, and Index
  • Programmability: Views, Functions, Procedures, and Triggers
  • Advanced T-SQL: CTEs, Windows, and Correlated Queries
  • Pattern Power: Regular Expressions in T-SQL
  • Fuzzy String Matching: Finding Similar Text
  • AI-Assisted SQL with GitHub Copilot Free
  • MCP: Connecting AI to Your Database

Domain 2: Secure, Optimize, and Deploy Database Solutions

  • Encryption: Always Encrypted and Column-Level
  • Dynamic Data Masking and Row-Level Security
  • Permissions, Auditing, and Passwordless Access
  • Transaction Isolation and Concurrency
  • Query Performance: Plans, DMVs, and Query Store
  • SQL Database Projects: Build and Validate
  • CI/CD Pipelines for SQL Databases
  • Data API Builder: REST and GraphQL from SQL
  • Securing AI and API Endpoints
  • Change Detection: CES, CDC, and Change Tracking
  • Azure Integration and Monitoring

Domain 3: Implement AI Capabilities in Database Solutions

  • External AI Models: Choose, Create, Manage
  • Embeddings: Design, Chunk, and Generate
  • Choose Your Search Strategy
  • Vector Data: Types, Indexes, and Storage
  • Vector Search: Distance, ANN, and ENN
  • Hybrid Search and Reciprocal Rank Fusion
  • RAG with SQL: Prompt, Process, Respond

DP-800 Study Guide

Domain 1: Design and Develop Database Solutions

  • Table Design: Columns, Types, and Indexes Free
  • Constraints: Protecting Your Data Free
  • Specialised Tables and Graph Queries Free
  • JSON in SQL: Store, Query, and Index
  • Programmability: Views, Functions, Procedures, and Triggers
  • Advanced T-SQL: CTEs, Windows, and Correlated Queries
  • Pattern Power: Regular Expressions in T-SQL
  • Fuzzy String Matching: Finding Similar Text
  • AI-Assisted SQL with GitHub Copilot Free
  • MCP: Connecting AI to Your Database

Domain 2: Secure, Optimize, and Deploy Database Solutions

  • Encryption: Always Encrypted and Column-Level
  • Dynamic Data Masking and Row-Level Security
  • Permissions, Auditing, and Passwordless Access
  • Transaction Isolation and Concurrency
  • Query Performance: Plans, DMVs, and Query Store
  • SQL Database Projects: Build and Validate
  • CI/CD Pipelines for SQL Databases
  • Data API Builder: REST and GraphQL from SQL
  • Securing AI and API Endpoints
  • Change Detection: CES, CDC, and Change Tracking
  • Azure Integration and Monitoring

Domain 3: Implement AI Capabilities in Database Solutions

  • External AI Models: Choose, Create, Manage
  • Embeddings: Design, Chunk, and Generate
  • Choose Your Search Strategy
  • Vector Data: Types, Indexes, and Storage
  • Vector Search: Distance, ANN, and ENN
  • Hybrid Search and Reciprocal Rank Fusion
  • RAG with SQL: Prompt, Process, Respond
Domain 1: Design and Develop Database Solutions Premium ⏱ ~15 min read

Advanced T-SQL: CTEs, Windows, and Correlated Queries

Write powerful queries with common table expressions, window functions for ranking and running totals, correlated subqueries, and structured error handling.

Queries that go beyond SELECT…WHERE

☕ Simple explanation

Think of building with LEGO.

Basic queries are like a single LEGO brick — useful but limited. CTEs let you build in stages: “first build the base, then put the walls on top.” Window functions let you peek at the rows around you: “what is my rank compared to everyone else?” Correlated subqueries ask a question for each row: “for this customer, how many orders do they have?” And error handling is your safety net — when something goes wrong, catch it gracefully instead of crashing.

The DP-800 exam expects fluency in advanced T-SQL patterns. CTEs break complex queries into readable stages and enable recursive queries. Window functions (ROW_NUMBER, RANK, SUM OVER, LAG, LEAD) perform calculations across row sets without collapsing them. Correlated subqueries reference the outer query row-by-row. Error handling with TRY/CATCH, THROW, and XACT_ABORT ensures transactional integrity.

Common Table Expressions (CTEs)

A CTE is a temporary, named result set defined within a single statement. Think of it as a “scratchpad query” you can reference in the main query.

-- Basic CTE: find customers who spent more than average
WITH CustomerSpending AS (
    SELECT CustomerId, SUM(Amount) AS TotalSpent
    FROM Orders
    GROUP BY CustomerId
)
SELECT c.FullName, cs.TotalSpent
FROM CustomerSpending cs
INNER JOIN Customers c ON cs.CustomerId = c.CustomerId
WHERE cs.TotalSpent > (SELECT AVG(TotalSpent) FROM CustomerSpending);

Recursive CTEs

Recursive CTEs reference themselves — perfect for hierarchical data like org charts, bill of materials, or category trees.

-- Walk the org chart from CEO down
WITH OrgChart AS (
    -- Anchor: start at the top (no manager)
    SELECT EmployeeId, Name, ManagerId, 0 AS Level
    FROM Employees
    WHERE ManagerId IS NULL

    UNION ALL

    -- Recursive: find direct reports of each level
    SELECT e.EmployeeId, e.Name, e.ManagerId, oc.Level + 1
    FROM Employees e
    INNER JOIN OrgChart oc ON e.ManagerId = oc.EmployeeId
)
SELECT Level, Name FROM OrgChart ORDER BY Level, Name;
💡 Exam tip: CTE vs subquery vs temp table

CTEs are not materialised — they are expanded inline like subqueries. If you reference the same CTE multiple times, SQL Server may execute it multiple times. For large intermediate results referenced repeatedly, a temp table or table variable may perform better.

Use CTEs for: readability, recursive queries, one-time intermediate results. Use temp tables for: large intermediate results referenced multiple times, when you need indexes on intermediate data.

Window functions

Window functions perform calculations across a set of rows related to the current row — without collapsing rows like GROUP BY does.

-- Ranking functions
SELECT
    Name,
    Department,
    Salary,
    ROW_NUMBER() OVER (ORDER BY Salary DESC) AS OverallRank,
    RANK() OVER (PARTITION BY Department ORDER BY Salary DESC) AS DeptRank,
    DENSE_RANK() OVER (PARTITION BY Department ORDER BY Salary DESC) AS DeptDenseRank
FROM Employees;

ROW_NUMBER vs RANK vs DENSE_RANK

SalaryROW_NUMBERRANKDENSE_RANK
100,000111
90,000222
90,000322
80,000443
  • ROW_NUMBER: always unique (1, 2, 3, 4)
  • RANK: ties get the same rank, then skips (1, 2, 2, 4)
  • DENSE_RANK: ties get the same rank, no skip (1, 2, 2, 3)

Running totals and moving averages

-- Running total and previous month comparison
SELECT
    OrderMonth,
    MonthlyRevenue,
    SUM(MonthlyRevenue) OVER (ORDER BY OrderMonth) AS RunningTotal,
    LAG(MonthlyRevenue, 1) OVER (ORDER BY OrderMonth) AS PreviousMonth,
    MonthlyRevenue - LAG(MonthlyRevenue, 1) OVER (ORDER BY OrderMonth) AS MonthOverMonth
FROM MonthlySales;
Window functions — know when each is the right tool
FunctionWhat It DoesExample Use
ROW_NUMBER()Assigns unique sequential numberPagination, deduplication
RANK()Rank with gaps for tiesLeaderboards where ties share a position
DENSE_RANK()Rank without gapsTop-N queries where you want exactly N distinct ranks
SUM() OVERRunning totalCumulative revenue, account balance
AVG() OVERMoving averageTrend analysis over sliding windows
LAG()Previous row valueMonth-over-month comparison
LEAD()Next row valuePredicting next event, gap analysis
FIRST_VALUE()First value in the windowBaseline comparison
NTILE()Divides rows into N equal groupsQuartile/percentile analysis

Correlated subqueries

A correlated subquery references the outer query — it runs once per outer row.

-- Find employees who earn more than their department average
SELECT e.Name, e.Department, e.Salary
FROM Employees e
WHERE e.Salary > (
    SELECT AVG(e2.Salary)
    FROM Employees e2
    WHERE e2.Department = e.Department  -- Correlated: references outer query
);

The inner query depends on e.Department from the outer query, so it re-executes for each employee. For large tables, this can be slow — a CTE or window function alternative is often better:

-- Same result using a window function (usually faster)
WITH DeptAvg AS (
    SELECT Name, Department, Salary,
           AVG(Salary) OVER (PARTITION BY Department) AS AvgSalary
    FROM Employees
)
SELECT Name, Department, Salary FROM DeptAvg WHERE Salary > AvgSalary;

Error handling: TRY…CATCH

Structured error handling ensures your transactions are clean and your errors are informative.

BEGIN TRY
    BEGIN TRANSACTION;

    UPDATE Accounts SET Balance = Balance - 500 WHERE AccountId = 1;
    UPDATE Accounts SET Balance = Balance + 500 WHERE AccountId = 2;

    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;

    -- Re-throw with context, or log and throw custom error
    DECLARE @Msg NVARCHAR(4000) = ERROR_MESSAGE();
    DECLARE @Sev INT = ERROR_SEVERITY();
    DECLARE @State INT = ERROR_STATE();
    RAISERROR(@Msg, @Sev, @State);
END CATCH;

THROW vs RAISERROR

FeatureTHROWRAISERROR
SyntaxTHROW 50001, 'message', 1;RAISERROR('message', 16, 1);
Re-throw original errorTHROW; (no parameters)Must reconstruct with ERROR_MESSAGE()
SeverityAlways 16 (unless re-throwing)Configurable (0-25)
Terminates batch?Yes (with XACT_ABORT ON)Only at severity 20+
Recommended?Yes — modern, simplerLegacy, but still needed for variable severity
💡 Exam tip: SET XACT_ABORT ON

SET XACT_ABORT ON at the start of a stored procedure ensures that ANY error automatically rolls back the entire transaction. Without it, some errors leave the transaction open (partially committed), which can cause data corruption.

Best practice: always use SET XACT_ABORT ON with SET NOCOUNT ON at the top of stored procedures.

Question

What is the difference between ROW_NUMBER() and DENSE_RANK()?

Click or press Enter to reveal answer

Answer

ROW_NUMBER() assigns a unique number to every row (no ties). DENSE_RANK() assigns the same rank to tied rows and does not skip numbers. Example: salaries 100K, 90K, 90K, 80K get ROW_NUMBER 1,2,3,4 but DENSE_RANK 1,2,2,3.

Click to flip back

Question

What is a correlated subquery?

Click or press Enter to reveal answer

Answer

A subquery that references columns from the outer query. It executes once per row of the outer query (conceptually). Example: 'for each employee, find the average salary of their department.' Often slower than CTEs or window functions for large datasets.

Click to flip back

Question

When should you use THROW vs RAISERROR?

Click or press Enter to reveal answer

Answer

THROW is the modern approach — simpler syntax and supports re-throwing the original error with just 'THROW;'. Use RAISERROR when you need variable severity levels (0-25) or formatted messages with printf-style substitution. For new code, prefer THROW.

Click to flip back

Knowledge Check

Priya at Vault Bank needs to show each customer's transaction history with a running balance. Each row should show the transaction amount and the cumulative total up to that transaction, ordered by date. Which approach is correct?

Knowledge Check

Dev at PixelForge Studios has a stored procedure that transfers credits between user accounts. If any step fails, the entire transfer must be rolled back. Currently, some errors leave the transaction partially committed. What should Dev add?

🎬 Video coming soon

Next up: Pattern Power: Regular Expressions in T-SQL — use the new REGEXP functions to find, replace, and split text with pattern matching.

← Previous

Programmability: Views, Functions, Procedures, and Triggers

Next →

Pattern Power: Regular Expressions in T-SQL

Guided

I learn, I simplify, I share.

A Guide to Cloud YouTube Feedback

© 2026 Sutheesh. All rights reserved.

Guided is an independent study resource and is not affiliated with, endorsed by, or officially connected to Microsoft. Microsoft, Azure, and related trademarks are property of Microsoft Corporation. Always verify information against Microsoft Learn.