3

I want to know how to check if a specific column (e.g: date) exists in a specific table(e.g: myTable) in an Access database.

I've read this answer which offers a query which results in another query.

IF NOT EXISTS(SELECT * 
              FROM sys.columns 
              WHERE [name] = N'columnName' 
                AND [object_id] = OBJECT_ID(N'tableName'))
BEGIN
    ALTER TABLE ADD COLUMN MYCOLUMN
END

But what I need is a true/false result.

UPDATE 1

How can I do that in my C# application?

Maybe using SqlCommand.ExecuteScalar() or something else?

Community
  • 1
  • 1
Ghasem
  • 14,455
  • 21
  • 138
  • 171
  • @marc_s I get `Invalid SQL statement; expected 'DELETE', 'INSERT', 'PROCEDURE', 'SELECT', or 'UPDATE'.` error using `ExecuteScalar` or `ExecuteNonQuery` – Ghasem Nov 21 '15 at 09:33
  • Here's an answer for determining if a table exists in Access from C#. Maybe it will point you in a more helpful direction than SQL Server code: http://stackoverflow.com/a/4793675/121544 – Shannon Severance Nov 21 '15 at 09:35
  • 1
    Yes, you didn't mention in your original question that this was for **MS Access** ........ `SqlCommand` and this T-SQL code only works for SQL Server ..... – marc_s Nov 21 '15 at 09:39

6 Answers6

3

As Andre451 mentions in his answer, you can use Access DAO to inspect the Fields collection of the relevant TableDef object, like this:

// test data
string dbFileSpec = @"C:\Users\Public\Database1.accdb";
string tblName = "Clients";
string colName = "LastName";

// COM reference required for project:
// Microsoft Office 14.0 Access Database Engine Object Library
//
var dbe = new Microsoft.Office.Interop.Access.Dao.DBEngine();
Microsoft.Office.Interop.Access.Dao.Database db = dbe.OpenDatabase(dbFileSpec);
Microsoft.Office.Interop.Access.Dao.TableDef tbd = db.TableDefs[tblName];
bool colExists = false;
foreach (Microsoft.Office.Interop.Access.Dao.Field fld in tbd.Fields)
{
    if (fld.Name.Equals(colName, StringComparison.InvariantCultureIgnoreCase))
    {
        colExists = true;
        break;
    }
}
db.Close();

Console.WriteLine("Column " + (colExists ? "exists" : "does not exist"));
Community
  • 1
  • 1
Gord Thompson
  • 116,920
  • 32
  • 215
  • 418
3

Thanks to everyone who offered a solution, gathering up some of the answers, I came up with my own version of solution. Maybe it's not the best solution around, but at least I don't need an extra dll to add to the references or deal with some stored procedures Access won't support.

OleDbConnection con = new OleDbConnection("my database address");
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = con;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT TOP 1 date FROM myTable";
con.Open();
bool exists = true;
try
{
  var x = cmd.ExecuteScalar();
}
catch (Exception e)
{
  exists = false;
}
con.Close();
Ghasem
  • 14,455
  • 21
  • 138
  • 171
2

Try this:

BEGIN

IF NOT EXISTS(SELECT * FROM sys.columns 
        WHERE [name] = N'columnName' AND [object_id] = OBJECT_ID(N'tableName'))
SELECT 0
ELSE
SELECT 1 
END

To use in c#:

SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "StoredProcedure3";
con.Open();
var x = cmd.ExecuteScalar();
MessageBox.Show(x.ToString());
con.Close();

To use without stored procedure:

SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "IF NOT EXISTS(SELECT * FROM sys.columns WHERE [name] = N'columnName' AND [object_id] = OBJECT_ID(N'tableName')) SELECT 0 ELSE SELECT 1 ";
con.Open();
var x = (int)cmd.ExecuteScalar();
MessageBox.Show(x.ToString());
con.Close();
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
  • How can I do it in `c#`? – Ghasem Nov 21 '15 at 08:59
  • Am I suppose to replace `StoredProcedure3` by the real query? – Ghasem Nov 21 '15 at 09:19
  • @AlexJolig ... `StoredProcedure3` is the name of your Stored procedure. you can change it to yours. – Salah Akbari Nov 21 '15 at 09:21
  • @AlexJolig...If you don't want to use Stored Procedure try tis: `cmd.CommandType = CommandType.Text; cmd.CommandText = "IF NOT EXISTS(SELECT * FROM sys.columns WHERE [name] = N'columnName' AND [object_id] = OBJECT_ID(N'tableName')) SELECT 0 ELSE SELECT 1 ";` – Salah Akbari Nov 21 '15 at 09:23
  • Why are you using `.ExecuteScalar()` ?? This SQL doesn't return any data at all - use `.ExecuteNonQuery()` instead! – marc_s Nov 21 '15 at 09:31
  • 1
    @marc_s...Why not? It returns `0` or `1`. – Salah Akbari Nov 21 '15 at 09:32
  • I get `Invalid SQL statement; expected 'DELETE', 'INSERT', 'PROCEDURE', 'SELECT', or 'UPDATE'.` error using `ExecuteScalar` or `ExecuteNonQuery` – Ghasem Nov 21 '15 at 09:32
  • 2
    SQL Server code is not going to run inside an MS Access database. – Shannon Severance Nov 21 '15 at 09:33
  • @AlexJolig... as (marc_c) said: *you didn't mention in your original question that this was for MS Access*. My answer should works fine if you use SQL Server. – Salah Akbari Nov 21 '15 at 09:41
2

In case anyone requires this in the future, below is the method I use on my Access databases.

void CheckTableFields(OleDbConnection con)
{
    var table = "Company";
    var field = "Location";
    var sSQL = $"SELECT TOP 1 * FROM [{table}]";

    using (OleDbConnection con = new OleDbConnection("MsJetOledbConnectionString"))
    {
        con.Open();
        using (var cmd = new OleDbCommand(sSQL, con))
        {
            try
            {
                DataTable dtGen = new DataTable();
                dtGen.Load(cmd.ExecuteReader());

                System.Data.DataColumnCollection columns = dtGen.Columns;

                if (!columns.Contains(field))
                {
                    //Field NOT found - add new 'Location2' column
                    cmd.CommandText = $"ALTER TABLE [{table}] ADD COLUMN {field} TEXT(50)";
                    var result = cmd.ExecuteNonQuery();

                    WriteLine($"{DateTime.Now}:   Table Column {{{field}}} added successfully");
                }
                else
                {
                    WriteLine($"{DateTime.Now}:   Table Column {{{field}}}  already exists");
                }
            }
            catch (Exception ex)
            {
                WriteLine($"[DataService.CheckCompanyTableFields]  Error - {{{ex.Message}}}");
            }
        }
    }
}
PaulM8
  • 21
  • 4
  • Works perfectly except last line, I removed the false. ` WriteLine($"[DataService.CheckCompanyTableFields] Error - {{{ex.Message}}}", `false`); ` – Shane.A Apr 08 '22 at 04:08
1

In Access VBA you could use the TableDef.Fields collection. Don't know if you can use these objects from c#.

Why don't you simply do (pseudocode)

columnExists = True
try
    ExecuteSql "SELECT TOP 1 [Date] FROM myTable"
catch
    // Error: column doesn't exist
    columnExists = False
Andre
  • 26,751
  • 7
  • 36
  • 80
  • 1
    programming by errors? why do i find this not acceptable – webs Jun 12 '20 at 12:20
  • If the alternative is a loop over all fields (since the fields collection does not have an .Exists method), I find it perfectly acceptable. – Andre Nov 20 '20 at 11:31
0

Simple by:

select true

Complete Code:

IF NOT EXISTS(SELECT * FROM sys.columns 
        WHERE [name] = N'columnName' AND [object_id] = OBJECT_ID(N'tableName'))
    BEGIN
        select true
    END

ELSE

    BEGIN
        select false
    END
Shaharyar
  • 12,254
  • 4
  • 46
  • 66