2

I need to find the default value of a column in a SQL Server 2005 or 2008 database from .Net.

My first attempt was to execute the stored procedure:

sp_help @objname

Where @objname is the table. Then in the seventh table returned (the constraints table), I was going to use the value in constraint_keys for the default constraints. When I run this query from SQL Server Management Studio it behaves as intended, but when I run it from C# code, the column constraint_keys was null (although all the other columns were populated).

My second attempt was to use:

SELECT name, [text]
FROM syscomments com
    INNER JOIN syscolumns col ON com.id = col.cdefault
WHERE col.id = object_id(@Table)
    AND col.cdefault > 0

Which also works fine in SQL Server Management Studio. When I run it from .Net, however, it returns no rows.

Additional:

Example .Net code (using Enterprise Libraries):

    private DataTable GetDefaults(string tablename string database)
    {            
        var db = DatabaseEL.Create(database);

        string sql = @"
            SELECT name, [text]
            FROM syscomments com
                INNER JOIN syscolumns col ON com.id = col.cdefault
            WHERE col.id = object_id(@Table)
                AND col.cdefault > 0";

        using (var command = db.GetSqlStringCommand(sql))
        {
            db.AddInParameter(command, "@Table", DbType.String, tablename);

            return db.ExecuteDataTable(command);
        }
    }

Note that I have now also tried each of the following from the linked similar question:

SELECT 
name, object_definition(default_object_id) AS default_value
FROM sys.columns
WHERE object_id = object_id(@Table)
AND default_object_id != 0

and

SELECT
sc.name AS column_name, 
    sm.text AS default_value
FROM sys.sysobjects so
    JOIN sys.syscolumns sc ON sc.id = so.id
    LEFT JOIN sys.syscomments SM ON sm.id = sc.cdefault
WHERE so.xtype = 'U' 
AND SO.name = @Table
AND sm.text IS NOT NULL

They both worked in SSMS, but in .Net, the former had nulls in the default_value column, and the latter had no rows.

Paul
  • 16,285
  • 13
  • 41
  • 52
  • Sounds like a duplicate of http://stackoverflow.com/q/3817885/559467. That gives you the value in a SQL statement, which can be run from C#. If it does not have a default value, it will not return anything. – D.N. Feb 23 '11 at 17:43
  • Could you post the .Net code ? I doesn't make sense that it works from Management studio and not from .Net. – Sem Vanmeenen Feb 23 '11 at 17:46

5 Answers5

4

The answer seems to be to grant the user access to the db_ddladmin role. While db_datareader and db_datawriter are enough to run the necessary queries, they all return NULLs for default values if the user has no access to db_ddladmin.

The reason it worked for me from SQL Server Management Studio, of course, was because I was logged in as an administrative user.

Paul
  • 16,285
  • 13
  • 41
  • 52
1

One other SQL query you could try is:

select * from information_schema.columns
where table_catalog = 'MyDatabase'
and table_schema = 'dbo' -- or your schema
and table_name = 'MyTable';

The COLUMN_HASDEFAULT and COLUMN_DEFAULT values should give you the info you're looking for.

Andy White
  • 86,444
  • 48
  • 176
  • 211
  • select * from information_schema.columns returns no rows in SSMS for me in SQL Server 2005. – Paul Feb 23 '11 at 18:27
  • Hmm, interesting. Not sure what would cause that, but I guess this method won't work for you in that case. – Andy White Feb 23 '11 at 19:55
1

You can use the GetSchema method from the SqlConnection.

enter image description here

Tom Brothers
  • 5,929
  • 1
  • 20
  • 17
0

Use SqlCommand to do it. try:

System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
        cmd.CommandText = "MyTable";
        cmd.CommandType = System.Data.CommandType.TableDirect;
        cmd.ExecuteReader(System.Data.CommandBehavior.SchemaOnly);
Dustin Davis
  • 14,482
  • 13
  • 63
  • 119
  • I don’t think that’s supported in .Net 3.5. I got the exception: "The CommandType enumeration value, 512, is not supported by the .Net Framework SqlClient Data Provider.". – Paul Feb 23 '11 at 18:34
  • Try just a sql query then cmd.CommandText = "select top 1 * from MyTable"; cmd.CommandType = Text; – Dustin Davis Feb 23 '11 at 19:12
0

With this straight ADO.NET code, you can definitely retrieve the information needed, no problem:

public class ColumnAndDefault
{
    public string ColumnName { get; set; }
    public string DefaultDefinition { get; set; }
}

public class GetDefaultColumnValues
{
    public List<ColumnAndDefault> GetDefaultsForTable(string tablename, string connectionString)
    {
        List<ColumnAndDefault> results = new List<ColumnAndDefault>();

        string query =
            string.Format("SELECT name, object_definition(default_object_id) " +
            "FROM sys.columns " +
            "WHERE default_object_id <> 0 AND object_id = OBJECT_ID('{0}')", tablename);

        using(SqlConnection _con = new SqlConnection(connectionString))
        using(SqlCommand _cmd = new SqlCommand(query, _con))
        {
            _con.Open();

            using(SqlDataReader rdr = _cmd.ExecuteReader())
            {
                while(rdr.Read())
                {
                    if(!rdr.IsDBNull(0) && !rdr.IsDBNull(1))
                    {
                        string colName = rdr.GetString(0);
                        string defValue = rdr.GetString(1);

                        results.Add(
                           new ColumnAndDefault { ColumnName = colName, 
                                                  DefaultDefinition = defValue });
                    }
                }

                rdr.Close();
            }

            _con.Close();
        }


        return results;
    }
}

You can call this from your app like this:

static void Main(string[] args)
{
   // grab that from a config file in your real app!
   string connectionString = "server=(local);database=YourDB;Integrated Security=SSPI;";

   GetDefaultColumnValues getter = new GetDefaultColumnValues();

   List<ColumnAndDefault> columnDefaults = 
      getter.GetDefaultsForTable("YourTableNameHere", connectionString);
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • This didn’t work either. Got a SqlNullValueException on the line string defValue = rdr.GetString(1);. – Paul Feb 23 '11 at 22:22
  • @Paul: there's definitely something fishy in your system then..... anyway: updated my answer to **check** for NULL and avoid stepping into the NULL case - try again, please. – marc_s Feb 24 '11 at 05:28
  • Yes, I agree. I think it is something peculiar in my system. I might have to resort to turning off triggers, inserting an empty row in a transaction, selecting the default values, and rolling back :-S – Paul Feb 24 '11 at 08:50