how to pass DataTable with less columns to stored procedure when user defined table type in SQL server has default values of all columns set to null

StackOverflow https://stackoverflow.com/questions/12277410

Question

I have a stored proc which accepts user defined table type and default values for all the columns in the user defined data type is set to null. Now i am passing a dataTable with less columns to stored procedure from c# code expecting that the values for remaining columns will be set to null.

But i am getting this error: Trying to pass a table-valued parameter with 21 column(s) where the corresponding user-defined table type requires 77 column(s). This is the code

  SqlConnection conn = new SqlConnection("server=****; database=***;integrated security=SSPI");
  DataSet dataset=new DataSet();
  conn.Open();
  SqlCommand cmd = new SqlCommand("Insert");      
  cmd.CommandType = CommandType.StoredProcedure;
  cmd.Connection = conn;
  SqlParameter para = new SqlParameter();
  para.ParameterName = "@TableVar";
  para.SqlDbType = SqlDbType.Structured;
  //SqlParameter para=cmd.Parameters.AddWithValue("@TableVar",table);
  para.Value = table;
  cmd.Parameters.Add(para);
  cmd.ExecuteNonQuery();
Was it helpful?

Solution

You can use a SqlDataAdapter to create a DataTable matching the table type schema:

DataTable table = new DataTable();

// Declare a variable of the desired table type to produce a result set with it's schema.
SqlDataAdapter adapter = new SqlDataAdapter("DECLARE @tableType dbo.UserDefindTableType 
                                             SELECT * FROM @tableType", ConnectionString);

// Sets the DataTable schema to match dbo.UserDefindTableType .
adapter.FillSchema(table, SchemaType.Source);

You can then create DataRows with the all the default column values and just set the columns you know about:

DataRow row = table.NewRow();

// Set know columns...
row["ColumnName"] = new object();

// or check column exists, is expected type etc first
if (table.Columns.Contains("ColumnName") 
    && table.Columns["ColumnName"].DataType == typeof(string)) {
    row["ColumnName"] = "String";
}

table.Rows.Add(row);

OTHER TIPS

I'm having the same issue and the solution I'm working on is to run an extra SQL query to get the column definition and then fill up the DataTable with the missing columns, here is the SQL statement for a column definition on your table type:

select c.name, t.name as type, c.max_length as length from sys.table_types tt
inner join sys.columns c on c.object_id = tt.type_table_object_id
inner join sys.types t on t.system_type_id = c.system_type_id
where tt.name = @tabletypename
order by c.column_id

The C# code will be a bit more messy as you have to parse the return type (ie VARCHAR, INT, etc) into a SqlDbType enum if you want the solution to work for all table valued parameter defintions..

I would have thought stuff like this could have been better solved by Microsoft inside the SQL Server engine as its the next best way to import CSV files if you do not have write access to the local filesystem, but I want a single UDTT to cater for all CSV files not having to create a new table type every time I deal with a new file format. Anyways.. rant over.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top