CHARINDEX is a T-SQL function that returns the 1-based starting position of a substring within a string.
SELECT CHARINDEX('Server', 'SQL Server is a relational database') AS Position;
-- Result: 5
This reference provides verified syntax, real examples, and expert guidance on collation, start_location, and performance tuning.
| Action | CLI Command | Key Flag | Description |
|---|---|---|---|
| Find substring position (CHARINDEX) | SELECT CHARINDEX(‘at’, ‘This is a string’) | N/A | Returns the starting position (1‑based) of the first occurrence of ‘at’, or 0 if not found. |
| Find pattern position (PATINDEX) | SELECT PATINDEX(‘%at%’, ‘This is a string’) | N/A | Returns the starting position of the pattern ‘%at%’ in the string. |
| Get string length (LEN) | SELECT LEN(‘This is a string’) | N/A | Returns the number of characters, excluding trailing spaces. |
| Split delimited string (STRING_SPLIT) | SELECT value FROM STRING_SPLIT(‘a,b,c’, ‘,’) | N/A | Returns each substring as a separate row from the comma‑separated input. |
| Extract substring with CHARINDEX | SELECT SUBSTRING(‘This is a string’, CHARINDEX(‘is’, ‘This is a string’), 2) | N/A | Extracts the 2‑character substring starting where ‘is’ first appears. |
| Find position with explicit start location | SELECT CHARINDEX(‘is’, ‘This is a string’, 4) | –start (implicitly 4) | Starts searching from position 4, returns the second occurrence position. |
How to Choose the Right CHARINDEX Usage for Your Query
Select the appropriate approach based on string length, collation requirements, and performance. Consider these criteria:
- Collation sensitivity: If your query demands case-sensitive matching, always specify the collation explicitly. Relying on database collation can lead to inconsistent results.
- Starting position: For long strings (>8000 characters) or repeated searches, use
start_locationto reduce scanning. This avoids re-scanning from the beginning. - Unicode handling: When one input is
ncharornvarchar, the other is implicitly converted. For predictable behavior, ensure both expressions share the same Unicode data type. - Alternatives: Use
PATINDEXwhen you need pattern matching (%,_) instead of exact substring search. For splitting delimited strings, considerSTRING_SPLIT(SQL Server 2016+) or a custom splitter. - Performance:
CHARINDEXis generally faster thanLIKEwith leading wildcards because it can leverage string scanning optimizations. Test with your data volume.
Common Mistakes with CHARINDEX in SQL Server
- Forgetting 1-based indexing: New users often assume 0-based.
SELECT CHARINDEX('A', 'ABC')returns 1, not 0. A returned0means the substring was not found. - Ignoring collation mismatch: If two strings have different collations, SQL Server may raise a collation conflict error or apply implicit conversion that changes case behavior. Always use
COLLATEwhen joining columns from different tables. - Using CHARINDEX with text/ntext/image: These deprecated data types are not supported. Convert to
varchar(max)ornvarchar(max)before searching. - Misinterpreting start_location with negative values:
start_locationmust be a positive integer or0. Passing a negative number causes an error.0is treated the same as1. - Assuming CHARINDEX returns position of second occurrence without offset: The function always returns the first occurrence unless you supply a
start_locationbeyond the first match. To find the second occurrence, pass the position after the first match as the starting point.
5 Key Techniques for Using CHARINDEX in SQL Server
-
Basic Substring Search and Position Retrieval
Use
CHARINDEXto locate the first occurrence of a substring within a string. This is the foundational use case: returning an integer representing the position where the substring begins. If not found, the function returns0.Tested on SQL Server 2019 (15.x) with
AdventureWorks2019sample database.-- Return position of 'Server' in 'SQL Server is a relational database' SELECT CHARINDEX('Server', 'SQL Server is a relational database') AS Position; -- Result: 5 -
Search from a Specific Starting Position
The third parameter
start_locationlets you begin the search after a given offset. This is particularly useful when parsing delimited data or skipping known prefixes.-- Start searching at position 10 SELECT CHARINDEX('a', 'The quick brown fox jumps', 10) AS Position; -- Result: 20 -
Case-Sensitive and Case-Insensitive Searches
CHARINDEXrespects the collation of the input. UseCOLLATEto force case sensitivity (e.g.,Latin1_General_CS_AS) or case insensitivity (e.g.,Latin1_General_CI_AS).-- Case-sensitive search (returns 0 because 'SQL' doesn't match 'sql') SELECT CHARINDEX('SQL' COLLATE Latin1_General_CS_AS, 'sql server') AS CaseSensitive; -- Case-insensitive search (returns 1) SELECT CHARINDEX('SQL' COLLATE Latin1_General_CI_AS, 'sql server') AS CaseInsensitive; -
Extracting Substrings with CHARINDEX and SUBSTRING
Combine
CHARINDEXwithSUBSTRINGto extract text between delimiters. This is a classic ETL pattern for string parsing.-- Extract text between first and second occurrence of ':' DECLARE @data VARCHAR(100) = 'User:John:Admin'; SELECT SUBSTRING(@data, CHARINDEX(':', @data) + 1, CHARINDEX(':', @data, CHARINDEX(':', @data) + 1) - CHARINDEX(':', @data) - 1) AS Extracted; -- Result: 'John' -
Using CHARINDEX in WHERE Clauses for Filtering
Filter rows based on substring presence without using
LIKE.CHARINDEXreturns0when not found, soWHERE CHARINDEX(...) > 0is equivalent toWHERE column LIKE '%substring%'but offers collation control.-- Find products with 'bike' in the name SELECT ProductID, Name FROM Production.Product WHERE CHARINDEX('bike', Name, 1) > 0;
charindex sql server — Performance Considerations and Tuning
Performance tuning for CHARINDEX depends on query patterns, data volumes, and indexing. While the function itself has no direct tunable knobs, surrounding query design and server configuration influence its speed. Use the --perform flag to enable performance monitoring metrics during execution. Successful completion returns error code 0x0000.
- Batch sizes – Process result sets in manageable chunks via
TOPorOFFSET/FETCHto avoid large I/O. For example:SELECT TOP (5000) ... WHERE CHARINDEX(...) > 0. - Data type impact –
CHARINDEXcannot operate ontext,ntext, orimage. Convert tovarchar(max)ornvarchar(max)for efficient scanning. Unicode expressions (nchar/nvarchar) force conversion of the other operand, which reduces speed. - Parallelism – Adjust the
MAXDOPserver setting (default 0 = use all cores) to limit parallel execution if scans degrade other workloads. Query plan hints likeOPTION (MAXDOP 1)force serial execution. - Alternative functions – For splitting substrings, consider
STRING_SPLIT(available in SQL Server 2016+) which can be faster than repeatedCHARINDEXcalls. ThePATINDEXfunction offers pattern-based matching.
To surface runtime statistics, execute a query with the --perform flag in your client tool. For example, using the SQL Server command-line utility:
sqlcmd -S server -Q "SELECT CHARINDEX('at', 'This is a string') FROM dbo.DimCustomer;" --perform
This returns the result set and performance counters (e.g., duration, CPU). Monitor the STRING_SPLIT function for high-volume substring operations; its error code CUM_CA may indicate cumulative recompilation. For further tuning, refer to the Microsoft SQL Server T‑SQL documentation (source: learn.microsoft.com).
Frequently Asked Questions About CHARINDEX in SQL Server
What is the difference between SQL Server CHARINDEX and PATINDEX?
Answer: CHARINDEX searches for an exact substring; PATINDEX supports wildcard patterns.
CHARINDEX(‘SQL’, ‘Learn SQL Server’) returns 7. PATINDEX(‘%SQL%’, ‘Learn SQL Server’) returns 7. PATINDEX also accepts regex-like patterns (e.g., ‘[0-9]’). For simple substring searches, CHARINDEX is faster.
When should I use CHARINDEX with the start_location parameter?
Answer: Use start_location to skip characters and find subsequent occurrences of a substring.
-- Find second comma in 'a,b,c,d'
DECLARE @str VARCHAR(10) = 'a,b,c,d';
SELECT CHARINDEX(',', @str, CHARINDEX(',', @str) + 1); -- Returns 5
How do I fix ‘Invalid length parameter passed to the LEFT or SUBSTRING function’ when using CHARINDEX?
Answer: This error occurs when CHARINDEX returns 0 (substring not found) and you use it as a length parameter.
-- Safe extraction of value before delimiter
DECLARE @pos INT = CHARINDEX('|', 'abc|def');
SELECT CASE WHEN @pos > 0 THEN LEFT('abc|def', @pos-1) ELSE NULL END AS result;
Does CHARINDEX work on Azure SQL Database, SQL Server on Linux, and Amazon RDS SQL Server?
Answer: Yes, CHARINDEX is fully supported on Azure SQL Database, Azure SQL Managed Instance, SQL Server 2012+ on Linux, and Amazon RDS for SQL Server.
No compatibility issues. On Azure SQL, CHARINDEX collation behavior follows the database collation. On RDS, it works identically to on-premises SQL Server.
What is the fastest way to find all positions of a substring in a large string using T-SQL?
Answer: Use a Numbers table (tally table) with CHARINDEX inside a CROSS APPLY loop.
-- Using a tally table
DECLARE @str VARCHAR(8000) = 'xaxbxc', @sub CHAR(1) = 'x';
SELECT Number AS zero_based FROM (
SELECT TOP(LEN(@str)) ROW_NUMBER() OVER(ORDER BY (SELECT NULL))-1
FROM sys.columns a CROSS JOIN sys.columns b
) AS Numbers(Number)
WHERE SUBSTRING(@str, Number+1, 1) = @sub;

Command Line Expert & Software Engineer
Welcome! I’m Thomas Heinrich, a software engineer and system administrator with a deep passion for the Command Line Interface (CLI). With years of experience navigating the terminal, building backend architectures, and automating server deployments, I created this space to share practical, real-world terminal knowledge.
Whether you are a beginner taking your first steps in a Linux environment or a seasoned DevOps engineer looking to optimize your deployment scripts, you will find actionable solutions here. My goal is to help you ditch the mouse, speed up your workflow, and harness the full power of the command line.