SQL

Image source: online

In this article, we’ll dive deep into ten powerful SQL Server features: Common Table Expressions (CTEs), Window Functions, LATERAL Joins (CROSS APPLY / OUTER APPLY), GROUPING SETS, ROLLUP & CUBE, FILTER Clause in Aggregates, UPSERT (MERGE / INSERT...ON CONFLICT), JSON Support & JSON_TABLE, Computed / Generated Columns, TABLESAMPLE, and Partial Indexes.

For each feature, we’ll explore:

This article assumes familiarity with SQL Server, given your experience since 2009, but it’s structured to be accessible while diving into advanced applications. Let’s get started!

Table of Contents

  1. Common Table Expressions (CTEs) (#common-table-expressions-ctes)
  2. Window Functions (#window-functions)
  3. LATERAL Joins (CROSS APPLY / OUTER APPLY) (#lateral-joins-cross-apply--outer-apply)
  4. GROUPING SETS, ROLLUP & CUBE (#grouping-sets-rollup--cube)
  5. FILTER Clause in Aggregates (#filter-clause-in-aggregates)
  6. UPSERT (MERGE / INSERT...ON CONFLICT) (#upsert-merge--inserton-conflict)
  7. JSON Support & JSON_TABLE (#json-support--json_table)
  8. Computed / Generated Columns (#computed--generated-columns)
  9. TABLESAMPLE (#tablesample)
  10. Partial Indexes (#partial-indexes)
  11. Conclusion (#conclusion)

Common Table Expressions (CTEs)

What are CTEs?

Common Table Expressions (CTEs) are temporary result sets defined within a SQL query’s scope, allowing you to name and reuse a subquery multiple times in a single query. Introduced in SQL Server 2005, CTEs improve query readability and maintainability, especially for complex operations like recursive queries.Basic ExampleLet’s start with a simple CTE to calculate total sales per employee.

-- Sample Data
CREATE TABLE Sales (
    EmployeeID INT,
    SaleAmount DECIMAL(10, 2),
    SaleDate DATE
);
INSERT INTO Sales (EmployeeID, SaleAmount, SaleDate)
VALUES (1, 500.00, '2025-01-01'), (1, 300.00, '2025-01-02'),
       (2, 700.00, '2025-01-01'), (2, 200.00, '2025-01-03');

-- Basic CTE
WITH EmployeeSales AS (
    SELECT EmployeeID, SUM(SaleAmount) AS TotalSales
    FROM Sales
    GROUP BY EmployeeID
)
SELECT EmployeeID, TotalSales
FROM EmployeeSales
WHERE TotalSales > 500;

Output

EmployeeID | TotalSales
-----------|-----------
1          | 800.00
2          | 900.00

Advanced Example: Recursive CTERecursive CTEs are powerful for hierarchical data, such as organizational charts.

-- Sample Data: Employee Hierarchy
CREATE TABLE Employees (
    EmployeeID INT PRIMARY KEY,
    EmployeeName VARCHAR(50),
    ManagerID INT
);
INSERT INTO Employees (EmployeeID, EmployeeName, ManagerID)
VALUES (1, 'CEO', NULL), (2, 'Manager A', 1), (3, 'Manager B', 1),
       (4, 'Employee A1', 2), (5, 'Employee A2', 2), (6, 'Employee B1', 3);

-- Recursive CTE to build hierarchy
WITH EmployeeHierarchy AS (
    -- Anchor Member: Start with the CEO
    SELECT EmployeeID, EmployeeName, ManagerID, 0 AS Level
    FROM Employees
    WHERE ManagerID IS NULL
    UNION ALL
    -- Recursive Member: Get subordinates
    SELECT e.EmployeeID, e.EmployeeName, e.ManagerID, eh.Level + 1
    FROM Employees e
    INNER JOIN EmployeeHierarchy eh ON e.ManagerID = eh.EmployeeID
)
SELECT EmployeeID, EmployeeName, ManagerID, Level
FROM EmployeeHierarchy
ORDER BY Level, EmployeeName;

Output

EmployeeID | EmployeeName | ManagerID | Level
-----------|-------------|-----------|------
1          | CEO         | NULL      | 0
2          | Manager A   | 1         | 1
3          | Manager B   | 1         | 1
4          | Employee A1 | 2         | 2
5          | Employee A2 | 2         | 2
6          | Employee B1 | 3         | 2

Scenarios

Alternatives

Usage Cases

Performance Issues

Pros and ConsPros

Cons

Business Case Scenario: A retail company needs to analyze its organizational structure to assess reporting lines for a compensation review. A recursive CTE can map the hierarchy from CEO to entry-level employees, enabling HR to calculate bonuses based on levels or reporting chains. This approach is faster and more maintainable than manual reporting or multiple subqueries, saving time and reducing errors.

Window Functions

What are Window Functions?

Window Functions perform calculations across a set of rows (a “window”) related to the current row, without collapsing the result set like aggregates do. Introduced in SQL Server 2005 and enhanced in 2012, they’re ideal for ranking, running totals, and moving averages.Basic ExampleCalculate a running total of sales per employee.

-- Using Sales table from CTE example
SELECT EmployeeID, SaleAmount, SaleDate,
       SUM(SaleAmount) OVER (PARTITION BY EmployeeID ORDER BY SaleDate) AS RunningTotal
FROM Sales;

Output

EmployeeID | SaleAmount | SaleDate   | RunningTotal
-----------|------------|------------|-------------
1          | 500.00     | 2025-01-01 | 500.00
1          | 300.00     | 2025-01-02 | 800.00
2          | 700.00     | 2025-01-01 | 700.00
2          | 200.00     | 2025-01-03 | 900.00

Advanced Example: Ranking with Tie HandlingRank employees by sales within each month, handling ties with DENSE_RANK.

SELECT EmployeeID, SaleAmount, SaleDate,
       DENSE_RANK() OVER (PARTITION BY MONTH(SaleDate) ORDER BY SaleAmount DESC) AS SalesRank
FROM Sales
WHERE YEAR(SaleDate) = 2025;

Output (assuming more data)

EmployeeID | SaleAmount | SaleDate   | SalesRank
-----------|------------|------------|----------
2          | 700.00     | 2025-01-01 | 1
1          | 500.00     | 2025-01-01 | 2
1          | 300.00     | 2025-01-02 | 3
2          | 200.00     | 2025-01-03 | 4

Scenarios

Alternatives

Usage Cases

Performance Issues

Pros and Cons

Pros

Cons

Business Case Scenario: A sales team wants to identify top performers monthly to allocate bonuses. Using DENSE_RANK with window functions, the company can rank employees by sales within each month, automatically handling ties and providing clear insights for incentive programs. This avoids complex self-joins and improves query performance.

LATERAL Joins (CROSS APPLY / OUTER APPLY)

What are LATERAL Joins?

CROSS APPLY and OUTER APPLY, introduced in SQL Server 2005, allow a subquery or table-valued function to reference columns from the outer query, acting like a correlated subquery but with set-based processing. They’re SQL Server’s equivalent of LATERAL joins in other databases.

Basic Example: Retrieve the top 2 sales per employee.

SELECT e.EmployeeID, s.SaleAmount, s.SaleDate
FROM Employees e
CROSS APPLY (
    SELECT TOP 2 SaleAmount, SaleDate
    FROM Sales s
    WHERE s.EmployeeID = e.EmployeeID
    ORDER BY SaleAmount DESC
) s;

Output

EmployeeID | SaleAmount | SaleDate
-----------|------------|------------
1          | 500.00     | 2025-01-01
1          | 300.00     | 2025-01-02
2          | 700.00     | 2025-01-01
2          | 200.00     | 2025-01-03

Advanced Example: Table-Valued FunctionUse a table-valued function to calculate sales metrics.

CREATE FUNCTION dbo.GetSalesMetrics (@EmployeeID INT)
RETURNS TABLE AS
RETURN (
    SELECT SUM(SaleAmount) AS TotalSales, COUNT(*) AS SaleCount
    FROM Sales
    WHERE EmployeeID = @EmployeeID
);

SELECT e.EmployeeID, e.EmployeeName, sm.TotalSales, sm.SaleCount
FROM Employees e
CROSS APPLY dbo.GetSalesMetrics(e.EmployeeID) sm;

Output

EmployeeID | EmployeeName | TotalSales | SaleCount
-----------|-------------|------------|----------
1          | CEO         | NULL       | 0
2          | Manager A   | 800.00     | 2
3          | Manager B   | 900.00     | 2

Scenarios

Alternatives

Usage Cases

Performance Issues

Pros and Cons

Pros

Cons

Business Case Scenario: A marketing team needs the top 3 campaigns per region based on ROI. Using CROSS APPLY, the query can dynamically fetch the top campaigns for each region, simplifying reporting and enabling targeted marketing adjustments. This is more efficient than multiple subqueries and scales better for dynamic datasets.

GROUPING SETS, ROLLUP & CUBE

What are GROUPING SETS, ROLLUP, and CUBE?

Introduced in SQL Server 2008, GROUPING SETS, ROLLUP, and CUBE extend the GROUP BY clause to generate multiple grouping levels in a single query, ideal for hierarchical or multi-dimensional aggregations.

Basic Example: Summarize sales by employee and year.

SELECT EmployeeID, YEAR(SaleDate) AS SaleYear, SUM(SaleAmount) AS TotalSales
FROM Sales
GROUP BY GROUPING SETS ((EmployeeID, YEAR(SaleDate)), (EmployeeID), ());

Output

EmployeeID | SaleYear | TotalSales
-----------|----------|------------
1          | 2025     | 800.00
2          | 2025     | 900.00
1          | NULL     | 800.00
2          | NULL     | 900.00
NULL       | NULL     | 1700.00

Advanced Example: ROLLUP and CUBEUse ROLLUP for hierarchical totals and CUBE for all combinations.

-- ROLLUP: Hierarchical totals
SELECT EmployeeID, YEAR(SaleDate) AS SaleYear, SUM(SaleAmount) AS TotalSales
FROM Sales
GROUP BY ROLLUP (EmployeeID, YEAR(SaleDate));

-- CUBE: All combinations
SELECT EmployeeID, YEAR(SaleDate) AS SaleYear, SUM(SaleAmount) AS TotalSales
FROM Sales
GROUP BY CUBE (EmployeeID, YEAR(SaleDate));

ROLLUP Output

EmployeeID | SaleYear | TotalSales
-----------|----------|------------
1          | 2025     | 800.00
2          | 2025     | 900.00
1          | NULL     | 800.00
2          | NULL     | 900.00
NULL       | NULL     | 1700.00

CUBE Output (includes additional combinations):

EmployeeID | SaleYear | TotalSales
-----------|----------|------------
1          | 2025     | 800.00
2          | 2025     | 900.00
1          | NULL     | 800.00
2          | NULL     | 900.00
NULL       | 2025     | 1700.00
NULL       | NULL     | 1700.00

Scenarios

Alternatives

Usage Cases

Performance Issues

Pros and Cons

Pros

Cons

Business Case Scenario: A retail chain needs a sales report by store, region, and overall for budgeting. Using ROLLUP, the company generates a single query to produce all levels of aggregation, reducing development time and improving dashboard performance compared to multiple GROUP BY queries.

FILTER Clause in Aggregates

What is the FILTER Clause?

Introduced in SQL Server 2016, the FILTER clause allows conditional aggregation within aggregate functions (e.g., SUM, COUNT), making queries more concise than using CASE statements.

Basic Example: Count sales above a threshold.

SELECT EmployeeID,
       COUNT(*) AS TotalSales,
       COUNT(*) FILTER (WHERE SaleAmount > 400) AS HighValueSales
FROM Sales
GROUP BY EmployeeID;

Output

EmployeeID | TotalSales | HighValueSales
-----------|------------|---------------
1          | 2          | 1
2          | 2          | 1

Advanced Example: Calculate multiple conditional aggregates.

SELECT EmployeeID,
       SUM(SaleAmount) AS TotalSales,
       SUM(SaleAmount) FILTER (WHERE SaleDate >= '2025-01-02') AS RecentSales,
       COUNT(*) FILTER (WHERE SaleAmount > 500) AS PremiumSales
FROM Sales
GROUP BY EmployeeID;

Output

EmployeeID | TotalSales | RecentSales | PremiumSales
-----------|------------|-------------|-------------
1          | 800.00     | 300.00      | 0
2          | 900.00     | 200.00      | 1

Scenarios

Alternatives

Usage Cases

Performance Issues

Pros and Cons

Pros

Cons

Business Case Scenario: A logistics company tracks delivery performance, needing counts of on-time vs. late deliveries. Using FILTER, the query concisely calculates both metrics in one pass, reducing code complexity and improving report generation speed for operational dashboards.

UPSERT (MERGE / INSERT...ON CONFLICT)

What is UPSERT?

MERGE (introduced in SQL Server 2008) performs insert, update, or delete operations in a single statement based on a source-target comparison. SQL Server doesn’t natively support INSERT...ON CONFLICT (like PostgreSQL), so MERGE is the primary UPSERT mechanism.

Basic Example: Update or insert employee sales targets.

CREATE TABLE SalesTargets (
    EmployeeID INT PRIMARY KEY,
    TargetAmount DECIMAL(10, 2)
);

-- Source Data
CREATE TABLE NewTargets (
    EmployeeID INT,
    TargetAmount DECIMAL(10, 2)
);
INSERT INTO NewTargets VALUES (1, 1000.00), (3, 1200.00);

-- MERGE
MERGE INTO SalesTargets t
USING NewTargets n
ON t.EmployeeID = n.EmployeeID
WHEN MATCHED THEN
    UPDATE SET TargetAmount = n.TargetAmount
WHEN NOT MATCHED THEN
    INSERT (EmployeeID, TargetAmount)
    VALUES (n.EmployeeID, n.TargetAmount);

Output (in SalesTargets)

EmployeeID | TargetAmount
-----------|-------------
1          | 1000.00
3          | 1200.00

Advanced Example: Handle updates, inserts, and deletes with logging.

CREATE TABLE SalesTargetsLog (
    LogID INT IDENTITY(1,1),
    EmployeeID INT,
    Action VARCHAR(20),
    OldTarget DECIMAL(10, 2),
    NewTarget DECIMAL(10, 2),
    LogDate DATETIME
);

MERGE INTO SalesTargets t
USING NewTargets n
ON t.EmployeeID = n.EmployeeID
WHEN MATCHED AND n.TargetAmount != t.TargetAmount THEN
    UPDATE SET TargetAmount = n.TargetAmount
    OUTPUT deleted.EmployeeID, 'UPDATE', deleted.TargetAmount, inserted.TargetAmount, GETDATE()
    INTO SalesTargetsLog (EmployeeID, Action, OldTarget, NewTarget, LogDate)
WHEN NOT MATCHED THEN
    INSERT (EmployeeID, TargetAmount)
    VALUES (n.EmployeeID, n.TargetAmount)
    OUTPUT inserted.EmployeeID, 'INSERT', NULL, inserted.TargetAmount, GETDATE()
    INTO SalesTargetsLog (EmployeeID, Action, OldTarget, NewTarget, LogDate)
WHEN NOT MATCHED BY SOURCE THEN
    DELETE
    OUTPUT deleted.EmployeeID, 'DELETE', deleted.TargetAmount, NULL, GETDATE()
    INTO SalesTargetsLog (EmployeeID, Action, OldTarget, NewTarget, LogDate);

Output (in SalesTargetsLog)

LogID | EmployeeID | Action | OldTarget | NewTarget | LogDate
------|------------|--------|-----------|-----------|----------------
1     | 1          | UPDATE | 800.00    | 1000.00   | 2025-07-23...
2     | 3          | INSERT | NULL      | 1200.00   | 2025-07-23...

Scenarios

Alternatives

Usage Cases

Performance Issues

Pros and Cons

Pros

Cons

Business Case Scenario: A CRM system syncs customer data from an external API nightly. Using MERGE, the system updates existing records, inserts new ones, and logs changes in one operation, ensuring data consistency and auditability. This reduces processing time compared to separate INSERT and UPDATE statements.

JSON Support & JSON_TABLE

What is JSON Support?

SQL Server 2016 introduced JSON support for storing, querying, and manipulating JSON data. Functions like JSON_VALUE, JSON_QUERY, and OPENJSON (akin to JSON_TABLE) enable integration with semi-structured data.

Basic Example: Extract values from a JSON column.

CREATE TABLE Orders (
    OrderID INT PRIMARY KEY,
    OrderDetails NVARCHAR(MAX)
);
INSERT INTO Orders (OrderID, OrderDetails)
VALUES (1, '{"Customer": "John", "Amount": 500.00, "Items": ["Item1", "Item2"]}');

SELECT OrderID,
       JSON_VALUE(OrderDetails, '$.Customer') AS Customer,
       JSON_VALUE(OrderDetails, '$.Amount') AS Amount
FROM Orders;

Output

OrderID | Customer | Amount
--------|---------|--------
1       | John    | 500.00

Advanced Example: OPENJSONParse JSON arrays with OPENJSON.

SELECT OrderID, Customer, Item
FROM Orders
CROSS APPLY OPENJSON(OrderDetails, '$.Items')
WITH (Item NVARCHAR(50) '$') AS Items;

Output

OrderID | Customer | Item
--------|---------|-------
1       | John    | Item1
1       | John    | Item2

Scenarios

Alternatives

Usage Cases

Performance Issues

Pros and Cons

Pros

Cons

Business Case Scenario: An e-commerce platform stores product details (e.g., sizes, colors) in JSON to accommodate varying attributes. Using OPENJSON, the platform queries product options dynamically, enabling flexible search filters without schema changes, improving development speed and customer experience.

Computed / Generated Columns

What are Computed Columns?

Computed columns are virtual columns whose values are derived from expressions or functions, computed on-the-fly or persisted. They’re useful for automating calculations or denormalizing data.Basic ExampleCalculate total order value with tax.

CREATE TABLE OrderDetails (
    OrderID INT PRIMARY KEY,
    Quantity INT,
    UnitPrice DECIMAL(10, 2),
    TaxRate DECIMAL(5, 2),
    TotalWithTax AS (Quantity * UnitPrice * (1 + TaxRate / 100))
);
INSERT INTO OrderDetails (OrderID, Quantity, UnitPrice, TaxRate)
VALUES (1, 10, 50.00, 10);

SELECT * FROM OrderDetails;

Output

OrderID | Quantity | UnitPrice | TaxRate | TotalWithTax
--------|----------|-----------|---------|-------------
1       | 10       | 50.00     | 10.00   | 550.00

Advanced Example: Persisted Computed ColumnUse a persisted computed column for frequent queries.

CREATE TABLE OrderDetails (
    OrderID INT PRIMARY KEY,
    Quantity INT,
    UnitPrice DECIMAL(10, 2),
    TaxRate DECIMAL(5, 2),
    TotalWithTax AS (Quantity * UnitPrice * (1 + TaxRate / 100)) PERSISTED
);

CREATE INDEX IX_TotalWithTax ON OrderDetails(TotalWithTax);

SELECT * FROM OrderDetails WHERE TotalWithTax > 500;

Scenarios

Alternatives

Usage Cases

Performance Issues

Pros and Cons

Pros

Cons

Business Case Scenario: A financial system calculates loan interest based on principal and rate. A persisted computed column stores the interest, indexed for fast reporting. This reduces query time for dashboards and ensures consistent calculations, improving user experience and auditability.

TABLE SAMPLE

What is TABLESAMPLE?

TABLESAMPLE retrieves a random sample of rows from a table, useful for statistical analysis or testing on large datasets. It’s based on page-level sampling, introduced in SQL Server 2005.

Basic Example: Sample 10% of sales data.

SELECT * FROM Sales
TABLESAMPLE (10 PERCENT);

Output (varies due to randomness)

EmployeeID | SaleAmount | SaleDate
-----------|------------|------------
1          | 500.00     | 2025-01-01
2          | 200.00     | 2025-01-03

Advanced Example: Sample with repeatable results.

SELECT * FROM Sales
TABLESAMPLE (10 PERCENT) REPEATABLE (42);

Scenarios

Alternatives

Usage Cases

Performance Issues

Pros and Cons

Pros

Cons

Business Case Scenario: A retail company audits 10% of transactions for fraud detection. Using TABLESAMPLE, the system quickly retrieves a random sample, reducing processing time compared to full-table scans and enabling efficient compliance checks.

Partial Indexes

What are Partial Indexes?

Partial indexes (filtered indexes in SQL Server, introduced in 2008) index a subset of rows based on a WHERE condition, reducing index size and improving query performance.

Basic Example: Index active employees only.

CREATE INDEX IX_ActiveEmployees ON Employees(EmployeeName)
WHERE ManagerID IS NOT NULL;

Advanced Example: Index high-value sales.

CREATE INDEX IX_HighValueSales ON Sales(SaleAmount, SaleDate)
WHERE SaleAmount > 500;

SELECT SaleAmount, SaleDate
FROM Sales
WHERE SaleAmount > 500;

Scenarios

Alternatives

Usage Cases

Performance Issues

Pros and Cons

Pros

Cons

Business Case Scenario: A subscription service queries active users frequently. A partial index on IsActive = 1 reduces index size and speeds up queries, improving application performance and reducing server load compared to a full index.

Conclusion

SQL Server’s advanced features—CTEs, Window Functions, LATERAL Joins, GROUPING SETS, FILTER Clause, UPSERT, JSON Support, Computed Columns, TABLESAMPLE, and Partial Indexes—offer powerful tools for data manipulation, analysis, and optimization.

By mastering these features, you can write more efficient, maintainable, and flexible queries to solve complex business problems. Each feature has unique strengths and trade-offs, and understanding their performance implications and use cases ensures you choose the right tool for the job.This guide provides a foundation for leveraging these features in real-world scenarios, from hierarchical reporting to random sampling and semi-structured data handling. Experiment with the examples, optimize with indexing, and integrate these techniques into your SQL Server workflows to unlock their full potential.