SUBSTRING in SQL Server: Syntax, CHARINDEX and Examples

You’ve got a column of full names or emails, and you need one piece of each value. SUBSTRING in SQL Server does that: SUBSTRING(expression, start, length) returns length characters beginning at start, counting the first character as 1.

Quick answer: SELECT SUBSTRING('Hannah Brooks', 1, 6); returns Hannah. Pair it with CHARINDEX when the cut point moves.

SUBSTRING Syntax and the Sample Customers Table

Tested on SQL Server 2025 (17.0.1000.7) Developer, sqlcmd in VS Code. The column examples use this table:

CREATE TABLE dbo.Customers (
    CustID   int          PRIMARY KEY,
    FullName nvarchar(20) NOT NULL,
    Email    varchar(30)  NULL,
    Phone    varchar(12)  NOT NULL
);
INSERT INTO dbo.Customers VALUES
(1, N'Hannah Brooks',  'hannah.brooks@acmeco.com', '614-555-0142'),
(2, N'Tyler Reed',     'treed@ohiomail.net',       '937-555-0188'),
(3, N'Grace Miller',   'grace@millerbakes.com',    '512-555-0127'),
(4, N'Marcus Bennett', NULL,                       '214-555-0163'),
(5, N'Cher',           'cher@example.com',         '303-555-0190');

Cher has no space in her name and Marcus has no email, and I left both in on purpose because they break the naive queries you’ll write later.

SET NOCOUNT ON;
SELECT SUBSTRING('Hannah Brooks', 1, 6)  AS First6,
       SUBSTRING('Hannah Brooks', 8, 6)  AS From8,
       SUBSTRING('Hannah Brooks', 8, 50) AS PastEnd,
       SUBSTRING('Hannah Brooks', 8)     AS NoLength;

Four calls on a literal:

First6 From8  PastEnd       NoLength     
------ ------ ------------- -------------
Hannah Brooks Brooks        Brooks

You should see Hannah, then Brooks three times, because a length past the end just stops at the end. Skipping the length is new in SQL Server 2025. Older versions reject it.

How SUBSTRING Handles Start 0, Negative Start and NULL

Edge cases first:

SET NOCOUNT ON;
SELECT SUBSTRING('Hannah', 0, 3)   AS Start0,
       SUBSTRING('Hannah', -2, 5)  AS StartNeg2,
       SUBSTRING('Hannah', 20, 3)  AS PastLen,
       SUBSTRING('Hannah', 2, NULL) AS NullLen,
       SUBSTRING(CAST(NULL AS varchar(10)), 1, 3) AS NullText;
DECLARE @len int = -1, @x varchar(10);
BEGIN TRY
    SET @x = SUBSTRING('Hannah', 1, @len);
END TRY
BEGIN CATCH
    PRINT CONCAT('Msg ', ERROR_NUMBER(), ': ', ERROR_MESSAGE());
END CATCH;

Output:

Start0 StartNeg2 PastLen NullLen NullText
------ --------- ------- ------- --------
Ha     Ha                NULL    NULL    
Msg 537: Invalid length parameter passed to the LEFT or SUBSTRING function.
SQL Server SUBSTRING with start 0, negative start, start past the end, NULL length and Msg 537 for a negative length
Start 0 and -2 both return Ha; a negative length raises Msg 537

Start 0 with length 3 gave Ha, not Han. Positions before 1 still count, so you get start + length - 1 characters.

Start 20 returns an empty string. NULL in, NULL out.

A negative length from a variable raises Msg 537. My first try used a literal -1 instead, and that failed at compile time with Msg 536, which TRY can’t catch.

Extract the Email Domain (Text After a Delimiter)

CHARINDEX finds the @. SUBSTRING takes what’s before it and after it:

SET NOCOUNT ON;
SELECT Email,
       SUBSTRING(Email, 1, CHARINDEX('@', Email) - 1) AS UserName,
       SUBSTRING(Email, CHARINDEX('@', Email) + 1)    AS Domain
FROM dbo.Customers
WHERE CustID IN (1, 2, 4);

Result:

Email                     UserName                  Domain                   
------------------------- ------------------------- -------------------------
hannah.brooks@acmeco.com  hannah.brooks             acmeco.com               
treed@ohiomail.net        treed                     ohiomail.net             
NULL                      NULL                      NULL
SQL Server SUBSTRING with CHARINDEX splitting an email address into user name and domain
CHARINDEX finds the @, SUBSTRING takes each side

Marcus’s NULL email gives NULL, no error. To list users per domain, use STRING_AGG in SQL Server.

Split First and Last Name With SUBSTRING and CHARINDEX

Same idea with a space, until it meets Cher: CHARINDEX returns 0, the length becomes -1, and the query dies.

SET NOCOUNT ON;
BEGIN TRY
    SELECT SUBSTRING(FullName, 1, CHARINDEX(' ', FullName) - 1)
           AS FirstName
    FROM dbo.Customers WHERE CustID IN (4, 5);
END TRY
BEGIN CATCH
    PRINT CONCAT('Msg ', ERROR_NUMBER(), ': ', ERROR_MESSAGE());
END CATCH;
-- fix: append a space so CHARINDEX never returns 0
SELECT FullName,
  SUBSTRING(FullName, 1, CHARINDEX(' ', FullName + ' ') - 1)
      AS FirstName,
  SUBSTRING(FullName, CHARINDEX(' ', FullName + ' ') + 1, 20)
      AS LastName
FROM dbo.Customers WHERE CustID IN (1, 2, 5);

Output:

FirstName           
--------------------
Marcus              
Msg 537: Invalid length parameter passed to the LEFT or SUBSTRING function.
FullName             FirstName            LastName            
-------------------- -------------------- --------------------
Hannah Brooks        Hannah               Brooks              
Tyler Reed           Tyler                Reed                
Cher                 Cher
SQL Server SUBSTRING with CHARINDEX failing with Msg 537 on a one-word name, then splitting first and last names
Msg 537 on Cher, then the fixed first and last name split

Marcus came back before the error. Appending a space means CHARINDEX always finds one.

Check your work: Cher’s LastName is an empty string, not NULL. To swap text rather than cut it, use REPLACE in SQL Server.

SUBSTRING From the Right vs LEFT and RIGHT

SUBSTRING can’t count from the end. Compute the start with LEN, or use RIGHT:

SET NOCOUNT ON;
SELECT Phone,
       LEFT(Phone, 3)                     AS AreaCode,
       SUBSTRING(Phone, 1, 3)             AS AreaCode2,
       RIGHT(Phone, 4)                    AS Last4,
       SUBSTRING(Phone, LEN(Phone) - 3, 4) AS Last4b
FROM dbo.Customers
WHERE CustID <= 2;

Area code and last four digits, both ways:

Phone        AreaCode AreaCode2 Last4 Last4b
------------ -------- --------- ----- ------
614-555-0142 614      614       0142  0142  
937-555-0188 937      937       0188  0188
SQL Server SUBSTRING compared with LEFT and RIGHT on phone numbers, same area code and last four digits
LEFT and RIGHT match the SUBSTRING versions

Same values. I’d pick LEFT and RIGHT because they read better at a glance. LEN ignores trailing spaces, so on padded char columns check the column’s data type before doing LEN math.

Does SUBSTRING Work on varbinary, text and ntext?

Yes. For binary, varbinary, text and image, start and length count bytes, and text comes back as varchar, ntext as nvarchar and image as varbinary.

Those old types are deprecated; CONVERT them to the max types.

Common SUBSTRING Errors and How to Fix Them

ErrorCauseFix
Msg 537Negative length at run timeSearch col + ' '
Msg 536Negative literal lengthFix the constant
Msg 8116Untyped NULL as the stringCAST it to varchar

Slicing numbers? Do an int-to-string conversion first. Writing a slice into a short column raises string or binary data would be truncated.

Next step: on MariaDB, MariaDB SUBSTRING also accepts a negative start that counts from the end.

Frequently Asked Questions

Can start and length be bigint?

Yes. Values above 2,147,483,647 need a varchar(max) or varbinary(max) input, per SUBSTRING (Transact-SQL).

Does SUBSTRING in a WHERE clause use an index?

No, it runs on every row. Email LIKE 'grace%' returns the same rows and can seek an index.

Is SUBSTRING case-sensitive?

No, it only counts positions. CHARINDEX compares text and follows the column’s collation.