It's worth noting that you can you BETWEEN for this kind of problem.
-- Sample data
WITH E(N) AS (SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))x(x)),
iTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1))+999 FROM E a, E b, E c, E d),
sc(someCode) AS (SELECT CONCAT('A', N) FROM iTally UNION ALL SELECT CONCAT('B', N) FROM iTally)
SELECT SomeCode INTO #codes FROM sc;
-- Solution
SELECT someCode
FROM #codes
WHERE someCode BETWEEN 'A2000' AND 'A2999';
Update (20170713):
Sorry for the late update, I must the second comment below. I just read it.
It is correct that my WHERE clause would pick up the value "A22"; it would also pick up "A2X00". That said, if the if the format you are working with looks like this: CDDDD (with C being a character and D being digit) then my solution is correct and SARGable. This is one of the reasons it's best to include DDL when posting a SQL Question. Note this article.
Update #2
Re: the question about how I generated the sample data.
I like explaining this because it invlolves tally tables - one of my favorite SQL topics ans one too view developers have any knowledge of.
My sample data coded generates the values A1000, A1001, A1002... though ...B15638, B15639, B15640. This provides a mix of "good" and bad values for you to test my logic against.
Tally tables are indispensible. Here's three of my favorite articles on the topic:
The "Numbers" or "Tally" Table: What it is and how it replaces a loop -- Jeff Moden
Tally Tables in T-SQL -- Dwain Camps
Virtual Auxiliary Table of Numbers -- Itzik Ben-Gan
So here's what the code does:
- Creates 10 dummy values in the first CTE (E)
- Cross Joins the values to themselves three times in the second CTE (iTally)
This very quicky generates 10,000 rows (10*10*10*10)
Numbers the rows 1-10000 using ROW_NUMBER (still in the iTally CTE)
Cross joins the numbers 1-10000 to the Values "A" and "B" then concatinates the letters & numbers
Does a SELECT INTO to create a temp table to hold the values.
Notice I don't return the "dummy values" in my final SELECT statement; they only exist so that ROW_NUMBER() can generate the numbers.
ROW_NUMBER() requires an OVER (ORDER BY) clause - which can cause a sort in the execution plan and slow my query down. ORDER (BY )
acceptable syntax as far as SQL Server 2005+ is concerned and this circumvents that nasty sort.
On my laptop (an HP with 32gb, 4 2.8ghz CPU - 8 logical CPU, 7200 rpm disk) I can generate the numbers 1 to 1,000,000,000 in 70-90 seconds.
This is one of many reasons I love tally tables.