After connecting to the database, can I get the name of all the columns that were returned in my SqlDataReader
?
11 Answers
var reader = cmd.ExecuteReader();
var columns = new List<string>();
for(int i=0;i<reader.FieldCount;i++)
{
columns.Add(reader.GetName(i));
}
or
var columns = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList();

- 35,279
- 21
- 87
- 141
-
81it's insane that there is no enumerable interface that lets you iterate through the columns. – JohnFx Jun 16 '11 at 04:35
-
67A bit shorter: `columns = Enumerable.Range(0, reader.FieldCount) .Select(reader.GetName).ToList();` – Oleks May 23 '13 at 14:05
-
2This works great. I also found out that my column names were all uppercase unless I used quotes around the column name. `SELECT id AS "MyId" FROM table;` – styfle Jul 13 '13 at 00:02
-
sir its returning all columnnames in lowercase. Column names in table are all uppercase like OBJECTID and reader is returning lowercase like objectid – Muneem Habib Nov 17 '15 at 11:30
-
how does this enumerable.range().select work in vb.net? any ideas? – swe Jan 16 '17 at 09:11
-
2its Dim columns() As String = Enumerable.Range(0, cTab.FieldCount).Select(Function(n) cTab.GetName(n)).ToArray – swe Jan 16 '17 at 09:36
-
If I remember correctly (which is doubtful), whether column names are returned in all lower case or all upper case is specific to the database you're using. PostgreSQL, which I use most of the time, gives them in lower case, and SQL Server gives them in upper case. Any corrections to this statement will be gratefully appreciated. – ROBERT RICHARDSON Jul 16 '18 at 13:53
-
1@ROBERTRICHARDSON Unless specified otherwise, SQL Server returns column names as-is. – Tom Lint Oct 06 '20 at 09:34
There is a GetName
function on the SqlDataReader
which accepts the column index and returns the name of the column.
Conversely, there is a GetOrdinal
which takes in a column name and returns the column index.

- 22,561
- 8
- 51
- 62

- 36,783
- 6
- 67
- 86
-
3Two reasons: first, the original poster has not chosen an answer yet, and secondly, there are other answers that give more detailed description of the problem's 'solution' then just the existence of the functionality. Personally, I like Steven Lyons' answer the best as not only does it talk about GetName but also goes into FieldType and DataType. – Stephen Wrighton Nov 26 '13 at 14:56
-
2`GetOrdinal` was perfect. I was looking for `GetName`, but much cleaner solution for my issue with `GetOrdinal`. – goodeye Jul 30 '15 at 01:52
You can get the column names from a DataReader.
Here is the important part:
for (int col = 0; col < SqlReader.FieldCount; col++)
{
Console.Write(SqlReader.GetName(col).ToString()); // Gets the column name
Console.Write(SqlReader.GetFieldType(col).ToString()); // Gets the column type
Console.Write(SqlReader.GetDataTypeName(col).ToString()); // Gets the column database type
}

- 568
- 8
- 29

- 8,138
- 1
- 28
- 27
Already mentioned. Just a LINQ answer:
var columns = reader.GetSchemaTable().Rows
.Cast<DataRow>()
.Select(r => (string)r["ColumnName"])
.ToList();
//Or
var columns = Enumerable.Range(0, reader.FieldCount)
.Select(reader.GetName)
.ToList();
The second one is cleaner and much faster. Even if you cache GetSchemaTable
in the first approach, the querying is going to be very slow.

- 30,738
- 21
- 105
- 131

- 70,104
- 56
- 326
- 368
-
-
-
I mean just an east way to get the values in the result set into a list, or perhaps the whole thing to an IEnumerable
object. – Travis Heeter Jul 27 '15 at 12:54 -
@TravisHeeter yes could do `reader.Cast
().ToList()`. I believe you could use `dynamic` keyword there instead of `IDataRecord` but with no benefit. `DataTable` was designed to ease onetime loading, so you could use that too but you lose the benefit of loading on demand (with data reader you could stop loading at any point), like `var dt = new DataTable(); dt.Load(reader); return dt.AsEnumerable().ToList();`. There are many libraries which can automate this for you, find them here http://stackoverflow.com/questions/11988441 and here http://stackoverflow.com/questions/1464883 – nawfal Jul 27 '15 at 13:12 -
I tried `reader.Cast
>` and `.Cast – Travis Heeter Jul 27 '15 at 13:23`, but it says, `Cannot convert method group 'Cast' to non-delegate type 'dynamic'. Did you intend to invoke the method?` what did I do wrong there? (I looked at your sources, but they required you to know the column name, which I don't) -
@TravisHeeter I dont know what you're missing, I think you're mistyping something. Try `using (var reader = command.ExecuteReader()) { return reader.Cast
().ToList(); } `. See this answer for converting generically to expando objects: http://stackoverflow.com/a/20223709/661933 – nawfal Jul 27 '15 at 13:56 -
I went ahead and started a question: http://stackoverflow.com/questions/31656938/how-to-convert-a-data-reader-to-dynamic-query-results – Travis Heeter Jul 27 '15 at 15:20
If you want the column names only, you can do:
List<string> columns = new List<string>();
using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SchemaOnly))
{
DataTable dt = reader.GetSchemaTable();
foreach (DataRow row in dt.Rows)
{
columns.Add(row.Field<String>("ColumnName"));
}
}
But if you only need one row, I like my AdoHelper addition. This addition is great if you have a single line query and you don't want to deal with data table in you code. It's returning a case insensitive dictionary of column names and values.
public static Dictionary<string, string> ExecuteCaseInsensitiveDictionary(string query, string connectionString, Dictionary<string, string> queryParams = null)
{
Dictionary<string, string> CaseInsensitiveDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
try
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
cmd.CommandText = query;
// Add the parameters for the SelectCommand.
if (queryParams != null)
foreach (var param in queryParams)
cmd.Parameters.AddWithValue(param.Key, param.Value);
using (SqlDataReader reader = cmd.ExecuteReader())
{
DataTable dt = new DataTable();
dt.Load(reader);
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn column in dt.Columns)
{
CaseInsensitiveDictionary.Add(column.ColumnName, row[column].ToString());
}
}
}
}
conn.Close();
}
}
catch (Exception ex)
{
throw ex;
}
return CaseInsensitiveDictionary;
}

- 30,738
- 21
- 105
- 131

- 4,687
- 1
- 32
- 25
-
1
-
2
-
7Asawyer, you should at least say why. I assume you're going to say you should use "throw;" instead so that you don't lose the original strack trace details. – Brent Rittenhouse Mar 28 '17 at 17:42
Use an extension method:
public static List<string> ColumnList(this IDataReader dataReader)
{
var columns = new List<string>();
for (int i = 0; i < dataReader.FieldCount; i++)
{
columns.Add(dataReader.GetName(i));
}
return columns;
}

- 4,342
- 6
- 50
- 87
For me, I would write an extension method like this:
public static string[] GetFieldNames(this SqlDataReader reader)
{
return Enumerable.Range(0, reader.FieldCount).Select(x => reader.GetName(x)).ToArray();
}

- 1,908
- 1
- 7
- 17
I use the GetSchemaTable method, which is exposed via the IDataReader interface.

- 30,738
- 21
- 105
- 131

- 3,105
- 2
- 29
- 34
-
yes here is an article about it: Getting schema info from the datareader https://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.110).aspx – Patrik Lindström Mar 08 '15 at 20:16
It is easier to achieve it in SQL
var columnsList = dbContext.Database.SqlQuery<string>("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'SCHEMA_OF_YOUE_TABLE' AND TABLE_NAME = 'YOUR_TABLE_NAME'").ToList();

- 876
- 2
- 11
- 34
You sure can.
protected void GetColumNames_DataReader()
{
System.Data.SqlClient.SqlConnection SqlCon = new System.Data.SqlClient.SqlConnection("server=localhost;database=northwind;trusted_connection=true");
System.Data.SqlClient.SqlCommand SqlCmd = new System.Data.SqlClient.SqlCommand("SELECT * FROM Products", SqlCon);
SqlCon.Open();
System.Data.SqlClient.SqlDataReader SqlReader = SqlCmd.ExecuteReader();
System.Int32 _columncount = SqlReader.FieldCount;
System.Web.HttpContext.Current.Response.Write("SqlDataReader Columns");
System.Web.HttpContext.Current.Response.Write(" ");
for ( System.Int32 iCol = 0; iCol < _columncount; iCol ++ )
{
System.Web.HttpContext.Current.Response.Write("Column " + iCol.ToString() + ": ");
System.Web.HttpContext.Current.Response.Write(SqlReader.GetName( iCol ).ToString());
System.Web.HttpContext.Current.Response.Write(" ");
}
}
This is originally from: http://www.dotnetjunkies.ddj.com/Article/B82A22D1-8437-4C7A-B6AA-C6C9BE9DB8A6.dcik

- 9,838
- 2
- 36
- 32
Odd that for such an old question no one proposed using the DbDataReaderExtensions.GetColumnSchema(DbDataReader) Method:
var colNames = reader.GetColumnSchema().Select((dbCol) => dbCol.ColumnName);
var colNames = (await reader.GetColumnSchemaAsync()).Select((col) => col.ColumnName);

- 34,009
- 10
- 83
- 174