Multiple Result Sets
One command can return several SELECT results. Reading them together saves round trips to the database.
On this page · 5 min · Intermediate
On this page
- In simple words
- Learning objectives
- Explanation
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 5 min
- Difficulty
- Intermediate
- Updated
- Oct 29, 2026
In simple words#
One phone call, three answers: “product details, related products and order count”. NextResult moves to the next answer.
- Result set
- The rows from one SELECT.
- NextResult()
- Move to the next result set.
- Benefit
- Fewer round trips to the database.
Learning objectives#
- Return several result sets from one batch or procedure
- Move between them with NextResult
- Build a page model from one call
- Understand MARS
Explanation#
A batch or stored procedure with several SELECT statements returns several result sets.
Read all rows of the first, then call NextResult (or NextResultAsync) to move to the next. It returns false when there are no more.
MultipleActiveResultSets=True (MARS) allows several open readers on one connection. It is rarely needed — reading sequentially is simpler and faster.
Code example: A product page in one round trip#
const string sql = """
SELECT Id, Name, Price FROM Products WHERE Id = @id;
SELECT TOP (3) Id, Name FROM Products
WHERE CategoryId = (SELECT CategoryId FROM Products WHERE Id = @id) AND Id <> @id;
SELECT COUNT(*) FROM Orders WHERE ProductId = @id;
""";
await using var cmd = new SqlCommand(sql, conn);
cmd.Parameters.Add("@id", SqlDbType.Int).Value = 1;
await using var r = await cmd.ExecuteReaderAsync();
await r.ReadAsync();
Console.WriteLine(quot;{r.GetString(1)} - ₹{r.GetDecimal(2)}");
await r.NextResultAsync();
while (await r.ReadAsync()) Console.WriteLine(quot; related: {r.GetString(1)}");
await r.NextResultAsync();
await r.ReadAsync();
Console.WriteLine(quot; sold {r.GetInt32(0)} times");
Laptop - ₹55000.00 related: Mouse related: Keyboard sold 12 times
This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.
Step-by-step explanation#
- Three SELECTs are sent in one batch.
- The first result set has the product.
- NextResultAsync moves to related products.
- The final result set has the order count.
Real-world use case#
A dashboard API loads totals, recent orders and low-stock alerts in one database round trip.
Common mistakes#
Remaining rows are skipped. That is fine if intended, but be deliberate.
Usually the real fix is to finish or dispose the first reader.
Best practices#
- Group related queries into one batch for fewer round trips
- Read result sets in a fixed order
- Document the result-set order of procedures
- Avoid MARS unless truly necessary
Remember this#
Several SELECTs → several result sets.
NextResult moves to the next one.
MARS = rarely needed.
Practice exercise#
Your task: Write a loop that prints the number of rows in each result set, whatever the count of sets.
Show solution
int set = 1;
do
{
int rows = 0;
while (await r.ReadAsync()) rows++;
Console.WriteLine(quot;Set {set++}: {rows} rows");
} while (await r.NextResultAsync());
Mini quiz#
Which method moves a reader to the next result set?
Want more? Practise all ADO.NET MCQs · ADO.NET interview questions
My notes#
Saved in this browser.