SQL Server CHOOSE Function: Syntax, Examples & Limits

Image showing blocks with different faces on (happy, excited, sad, etc)
Comments 0

Share to social media

The CHOOSE function in SQL Server returns a value from a list based on a 1-based index position: CHOOSE(2, ‘Yes’, ‘No’, ‘Maybe’) returns ‘No’. It’s useful for mapping integer codes to descriptive values in ETL processes, generating random test data with CHOOSE(ABS(CHECKSUM(NEWID())) % N + 1, …), and simplifying CASE expressions where the logic is purely positional.

CHOOSE returns NULL if the index is out of range and supports mixed data types (SQL Server uses data type precedence to determine the return type). This guide covers syntax, practical examples, and an important discovery about CHOOSE’s undocumented argument limit.

I preface a lot of what I write with whether or not it is for a “practical” use. One of the Simple Talk authors used this function in a forthcoming article. and I realized I hadn’t heard of it before (or I forgot about it… which is not completely unlikely.) The practical use was to generate some data and have at least a little variety to the values.

The CHOOSE function has this syntax.

A position (starting at 1) for the item_to_choose, then a list of 1 to N (where N isn’t strictly defined, but more on that later) that you can choose from.

So, if you execute the following:

The output will be.

—–
No

If there is no value at that position:

The output will be.

—–
NULL

You can get a random value if you do something like:

Execute this one or may times and you will get output of a random one of the values. (I have no idea why, but putting that exact expression from the CTE into a simple call sometimes led to NULL outputs:

Not sure why, but maybe that will be a later blog! Finally (for the random cases), if you do something like this:

You should get a pretty normal distribution of values in your output:

Value
———– ———-
3231 Yes
3406 No
3364 Maybe

So, CHOOSE can be useful for this sort of need to create random data from a specific set of values.

Practical Applications

It probably is more typical to use this when building an ETL system to translate values where you only have a number (and don’t intend to build a mapping table… which I might consider personally if you have more than a few values.)

For example, say you have this table (from WideWorldImporters)”

The contents of this table are:

Now, you could replace this in a query to load your data using:

Whether this is useful or not, I am going to leave it as a “thing you CAN do” for now. I have questions about the performance of such a strategy, but this is enough for now to show that you can use these tools this way.

Read also: Subqueries for value lookups in SQL SELECT

Let’s Get a Bit Stupid

Part of the fun of this sort of post for me is the “what is the limit?” sort of question. The documentation does not seem to give you a limit to the number of values… so I figured why not try. All the documentation says is:

List of comma-separated values of any data type. So, you can do:

Which will return 2, naturally.

Since this is feature I mostly see used with textual values, I wanted to see how may values you might be able to use. Since it wasn’t stated how many values you can include… I figured I should give it a go and see what the max is. So on my test machine with the following express version of SQL Server:

Microsoft SQL Server 2022 (RTM-CU18) (KB5050771) – 16.0.4185.3 (X64) Feb 28 2025 18:24:49 Copyright (C) 2022 Microsoft Corporation Express Edition (64-bit) on Windows 10 Enterprise 10.0 <X64> (Build 26100: ) (Hypervisor)

It is actually Windows 11, but whatever 🙂

So, I am going to try it out. I will generate a CHOOSE function call with increasingly large number of items such as:

This failed on 3175 with this error:

Msg 8631, Level 17, State 1, Line 80Internal error: Server stack limit has been reached. Please look for potentially deep nesting in your query and try to simplify it.

But 3174 items worked (Word wrap is turned on in the display, just copy as is to run yourself…if you dare!):

If you execute that code, you will get 3174.

I did check to see what would happen with longer pieces of text. If you change the STRING_AGG function to:

One thing changes, and not the number of values. Just the output. You get the same error message and the output is this:

——————
LongerValue3175

So, it actually went one more item further on the longer value (which was kind of weird)

It isn’t about the number of values in the expression, just the number of expressions. To take this one step farther, I tried changing the values to integers. I changed the temp table to have integer values, and then changed the STRING_AGG function to:

And it failed on 3174, again. Very strange.

Read also: Temporary tables for ETL staging in SQL Server

And Now, Just a Bit Weirder

Just to make sure that this wasn’t an Express issue, I did execute this on my test SQL Server running Developer Edition-

Microsoft SQL Server 2022 (RTM-CU18) (KB5050771) - 16.0.4185.3 (X64) Feb 28 2025 18:24:49 Copyright (C) 2022 Microsoft Corporation Developer Edition (64-bit) on Windows 10 Pro 10.0 <X64> (Build 26100: )

And it ran a step less. LongerValue3173 was where it got to.

Finally, I tried this on my Azure DB test database. Version info:

Microsoft SQL Azure (RTM) – 12.0.2000.8 Feb 27 2025 21:10:52 Copyright (C) 2024 Microsoft Corporation

I ran the test, but when it failed, the connection was killed:

Msg 40197, Level 20, State 1, Line 1
The service has encountered an error processing your request. Please try again. Error code 8631.

Msg 0, Level 20, State 0, Line 0
A severe error occurred on the current command. The results, if any, should be discarded.

Through a decent amount of trial and error (and changing the script to a permanent table that wouldn’t go away on a crash. It finished at LongerValue3971

Conclusion

CHOOSE is a pretty cool function that you can use to decode values or make some random values. It does have a limit, and I am not sure (yet?) if this is faster or slower than a JOIN when you have a reasonable number of items, but it could be useful in some ETL processes.

The whole thing with it causing a Level 20 error was weird, and quite interesting that there were different results in AzureDB, Express and Developer Editions, and weirder yet that the ceiling I reached was not set in the code.

If it is failing at this level, why not set a “2000 item limit?” or something similar? And something I currently do not have access to is an enterprise ready SQL Server to see what is going on. My AzureDB instance is the free forever version that lets me do testing.

There are few times that I miss being an MVP more than this. Not being able to ask someone at Microsoft directly is hard when you have such semi-inconsequential issues. Because no one should run up against this type of error. If you are doing 3000 items in a list like this, there needs to be a really good reason, and the only reason I could think of is shaving a few milliseconds off of a query. Which is something I will leave for another day.

Read also: PRODUCT function in SQL Server 2025

Fast, reliable and consistent SQL Server development…

…with SQL Toolbelt Essentials. 10 ingeniously simple tools for accelerating development, reducing risk, and standardizing workflows.
Learn more & try for free

FAQs: The SQL Server CHOOSE Function

1. What does the CHOOSE function do in SQL Server?

CHOOSE takes an integer index and a list of values, returning the value at that position (1-based). CHOOSE(1, ‘A’, ‘B’, ‘C’) returns ‘A’. If the index is out of range or NULL, it returns NULL. It’s a concise alternative to a CASE WHEN expression when you’re mapping consecutive integers to specific values.

2. How is CHOOSE different from CASE in SQL Server?

CHOOSE is specifically for positional lookups where the index maps directly to a list position. CASE WHEN is more flexible and can evaluate complex conditions, ranges, and non-sequential values. Use CHOOSE when mapping consecutive integers (1, 2, 3…) to values; use CASE for anything involving conditions, ranges, or non-sequential matching. CHOOSE is syntactically shorter but has an undocumented argument limit (approximately 3,900–4,000 items) that can cause a server-level crash.

Article tags

Load comments

About the author

Louis Davidson

See Profile

Louis is the former editor of Simple-Talk. Prior to that, has was a corporate database developer and data architect for a non-profit organization for 25 years! Louis has been a Microsoft MVP since 2004, and is the author of a series of SQL Server Database Design books, most recently Pro SQL Server Relational Database Design and Implementation.