SQL Server 2022 T-SQL Features Worth Using: GREATEST, DATE_BUCKET, IS DISTINCT FROM and More

SQL Server 2022 added a set of small T-SQL features that quietly remove years of workarounds. None of them are headline features, but you will use them every week once you know they exist. Most need database compatibility level 160 and are also available in Azure SQL Database.

SQL Server 2022 T-SQL Features Worth Using: GREATEST, DATE_BUCKET, IS DISTINCT FROM and More

GREATEST and LEAST

SELECT EmployeeID,
       GREATEST(LastLogin, LastPayslipView, LastProfileEdit) AS LastActivity,
       LEAST(BasicPay, PayCap) AS CappedPay
FROM dbo.EmployeeActivity;

No more nested CASE expressions or VALUES tricks to find the max across columns. NULLs are ignored unless all arguments are NULL.

IS [NOT] DISTINCT FROM

SELECT * FROM dbo.Employees e
JOIN staging.Employees s ON s.EmployeeID = e.EmployeeID
WHERE e.Email IS DISTINCT FROM s.Email;

A NULL-safe comparison: two NULLs are treated as equal, NULL vs a value as different. Perfect for change detection without ISNULL(col, '') hacks.

DATETRUNC

SELECT DATETRUNC(MONTH, OrderDate) AS MonthStart, SUM(Amount)
FROM dbo.Orders
GROUP BY DATETRUNC(MONTH, OrderDate);

Truncates a date to year, quarter, month, week, day, hour and so on, replacing the old DATEADD(MONTH, DATEDIFF(MONTH, 0, d), 0) idiom.

DATE_BUCKET

SELECT DATE_BUCKET(MINUTE, 15, EventTime) AS Slot, COUNT(*)
FROM dbo.ApiCalls
GROUP BY DATE_BUCKET(MINUTE, 15, EventTime);

Groups times into fixed-width buckets (every 15 minutes, every 2 weeks). Great for monitoring and time-series charts.

The WINDOW clause

SELECT EmployeeID, PayPeriod, GrossPay,
       SUM(GrossPay) OVER w AS RunningTotal,
       AVG(GrossPay) OVER w AS RunningAvg
FROM dbo.Payslips
WINDOW w AS (PARTITION BY EmployeeID ORDER BY PayPeriod
             ROWS UNBOUNDED PRECEDING);

Define a window once and reuse it, instead of repeating the same OVER clause.

STRING_SPLIT with ordinal, and TRIM with characters

SELECT value, ordinal FROM STRING_SPLIT('a,b,c', ',', 1);
SELECT TRIM('0' FROM '000123000');           -- '123'
SELECT LTRIM('xxABC', 'x');                  -- 'ABC'

The new enable_ordinal argument finally tells you the position of each item.

GENERATE_SERIES

SELECT value FROM GENERATE_SERIES(1, 12);

Produces a sequence of numbers without a tally table or recursive CTE.

JSON improvements

SELECT JSON_OBJECT('id': EmployeeID, 'name': Name) FROM dbo.Employees;
SELECT JSON_ARRAY(1, 2, 3);
SELECT * FROM dbo.Events WHERE ISJSON(Payload, OBJECT) = 1;

JSON_OBJECT and JSON_ARRAY build JSON directly, and ISJSON can check the type.

APPROX_PERCENTILE_CONT

Approximate median and percentiles on huge tables using very little memory, ideal for dashboards where exactness to the last row does not matter.

How to start using them

ALTER DATABASE CURRENT SET COMPATIBILITY_LEVEL = 160;

Raise the level carefully (with Query Store watching for plan regressions), then start replacing old workarounds as you touch the code.

Related reading:

Comments

Popular posts from this blog

How to Read a SQL Server Execution Plan (Beginner's Guide)

SARGable Queries in SQL Server: Why Functions in WHERE Slow You Down

SQL Server Statistics Explained: Why Your Query Plans Go Wrong