Question

Back when I only had one table in my .sdf file, this code worked fine:

const string sdfPath = @"\Program Files\duckbilled\Platypus.sdf";
string dataSource = string.Format("Data Source={0}", sdfPath);

if (!File.Exists(sdfPath))
{
    using (var engine = new SqlCeEngine(dataSource))
    {
        engine.CreateDatabase();
    }
    using (var connection = new SqlCeConnection(dataSource))
    {
        connection.Open();
        using (var command = new SqlCeCommand())
        {
            command.Connection = connection;
            command.CommandText =
                "CREATE TABLE Platydudes (Id int NOT NULL, BillSize smallint NOT NULL, Description nvarchar(255)";
            command.ExecuteNonQuery();
        }
    }
}

...but now I need to know, not whether the database file (Platypus.sdf) exists, but whether a particular table (such as Platydudes) exists in that table/file. Is there a way to determine that?

UPDATE

The 'IF NOT EXISTS' clause in the query causes a runtime exception. This code:

using (var connection = new SqlCeConnection(dataSource))
{
    connection.Open();
    using (var command = new SqlCeCommand())
    {
        command.Connection = connection;
        command.CommandText = "IF NOT EXISTS( SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'InventoryItems') " +
            "CREATE TABLE InventoryItems (Id nvarchar(50) NOT NULL, PackSize smallint NOT NULL, Description nvarchar(255), DeptDotSubdept numeric, UnitCost numeric, UnitList numeric, UPCCode nvarchar(50), UPCPackSize smallint, CRVId int);";
        command.ExecuteNonQuery();
    }
}

...causes this exception to be thrown: There was an error parsing the query. [ Token line number = 1, Token line offset = 1, Token in error = IF ]

So obviously the "IF" business is unwanted by the query parser. Is there another way to only create the table if it doesn't already exist? Or should I, each time, first delete the table then recreate it? IOW, should I do this:

using (var connection = new SqlCeConnection(dataSource))
{
    connection.Open();
    using (var command = new SqlCeCommand())
    {
        command.Connection = connection;
        command.CommandText = "DELETE InventoryItems";
        command.ExecuteNonQuery();
    }
    using (var command = new SqlCeCommand())
    {
        command.Connection = connection;
        command.CommandText = "CREATE TABLE InventoryItems (Id nvarchar(50) NOT NULL, PackSize smallint NOT NULL, Description nvarchar(255), DeptDotSubdept numeric, UnitCost numeric, UnitList numeric, UPCCode nvarchar(50), UPCPackSize smallint, CRVId int);";
        command.ExecuteNonQuery();
    }
}

?

UPDATE 2

To answer my question above in the first update: NOPE! If I do that, I get "The specified table already exists" on the second call to .ExecuteNonQuery().

UPDATE 3

In response to Shiva's comment to my answer:

This (reusing the command object) fails the same way ("table already exists"):

using (var command = new SqlCeCommand())
{
    command.Connection = connection;
    command.CommandText = "DELETE InventoryItems";
    command.ExecuteNonQuery();
    command.CommandText = "CREATE TABLE InventoryItems (Id nvarchar(50) NOT NULL, PackSize smallint NOT NULL, Description nvarchar(255), DeptDotSubdept numeric, UnitCost numeric, UnitList numeric, UPCCode nvarchar(50), UPCPackSize smallint, CRVId int);";
    command.ExecuteNonQuery();
}
Was it helpful?

Solution

SQL Compact doesn't like much for logic inside a SQL statement, so Shiva's answer probably won't pass the parser. He's on the right course, though. You can to do it in two steps:

Here's the TableExists method from the SQL Compact implementation of the OpenNETCF ORM:

public override bool TableExists(string tableName)
{
    var connection = GetConnection(true);
    try
    {
        using (var command = GetNewCommandObject())
        {
            command.Transaction = CurrentTransaction as SqlCeTransaction;
            command.Connection = connection;
            var sql = string.Format(
                    "SELECT COUNT(*) FROM information_schema.tables WHERE table_name = '{0}'", 
                     tableName);
            command.CommandText = sql;
            var count = Convert.ToInt32(command.ExecuteScalar());

            return (count > 0);
        }
    }
    finally
    {
        DoneWithConnection(connection, true);
    }
}

Obviously it's not complete for your case, but it's pretty easy to understand. CurrentTransaction could easily be null. GetNewCommandObject simply returns a new SqlCeCommand instance. GetConnection simply could return a new SqlCeConnection instance. DoneWithConnection could be a NOP. Basiocally these are all handling the fact that the ORM supports a plethora of backing stores. The kernel of info you need is the SQL that I pass in and how I determine the true/false return.

My (untested in a compiler) guess to the resulting method would be something like this:

public bool TableExists(SqlCeConnection connection, string tableName)
{
    using (var command = new SqlCeCommand())
    {
        command.Connection = connection;
        var sql = string.Format(
                "SELECT COUNT(*) FROM information_schema.tables WHERE table_name = '{0}'", 
                 tableName);
        command.CommandText = sql;
        var count = Convert.ToInt32(command.ExecuteScalar());
        return (count > 0);
    }
}

OTHER TIPS

If you want check if a Table exist you must use TABLE_SCHEMA

IF (EXISTS (SELECT * 
             FROM INFORMATION_SCHEMA.TABLES 
             WHERE TABLE_SCHEMA = 'TheSchema' 
             AND  TABLE_NAME = 'TheTable'))
BEGIN
--Do Stuff
END

Using Database helper:

var db = Database.Open("MyDatabase");
var sql = @"SELECT Count(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'MyTable'"
var count = db.QueryValue(sql);
if(count.Equals(1)){
    //table exists
}

Based on Shiva's answer, I will do something like this:

if (!File.Exists(sdfPath))
{
    using (var engine = new SqlCeEngine(dataSource))
    {
        engine.CreateDatabase();
    }
}

using (var connection = new SqlCeConnection(dataSource))
{
    connection.Open();
    using (var command = new SqlCeCommand())
    {
        command.Connection = connection;
        command.CommandText ="IF NOT EXISTS( SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Platydudes') " 
                           + "CREATE TABLE Platydudes (Id int NOT NULL, BillSize smallint NOT NULL, Description nvarchar(255) )";
        command.ExecuteNonQuery();
    }
}

...repeating "using (var connection = ..." sections as needed for each table (Platypups, Platypops, &c)

UPDATE

Using ctacke's code, I now have this:

public static void ConditionallyCreateTables()
{
    const string sdfPath = @"\Program Files\duckbilled\Platypus.sdf";
    string dataSource = string.Format("Data Source={0}", sdfPath);

    if (!File.Exists(sdfPath))
    {
        using (var engine = new SqlCeEngine(dataSource))
        {
            engine.CreateDatabase();
        }
    }
    using (var connection = new SqlCeConnection(dataSource))
    {
        connection.Open();
        using (var command = new SqlCeCommand())
        {
            command.Connection = connection;

            if (!TableExists(connection, "InventoryItems"))
            {
                command.CommandText = "CREATE TABLE InventoryItems (Id nvarchar(50) NOT NULL, PackSize smallint NOT NULL, Description nvarchar(255), DeptDotSubdept numeric, UnitCost numeric, UnitList numeric, UPCCode nvarchar(50), UPCPackSize smallint, CRVId int);";
                command.ExecuteNonQuery();
            }

            if (!TableExists(connection, "Departments"))
            {
                command.CommandText = "CREATE TABLE Departments (Id int NOT NULL, DeptNum int NOT NULL, DepartmentName nvarchar(255))";
                command.ExecuteNonQuery();
            }

            if (!TableExists(connection, "Subdepartments"))
            {
                command.CommandText = "CREATE TABLE Subdepartments (Id int NOT NULL, DeptId int NOT NULL, SubdeptId int NOT NULL, DepartmentName nvarchar(255))";
                command.ExecuteNonQuery();
            }

            if (!TableExists(connection, "Redemptions"))
            {
                command.CommandText = "CREATE TABLE Redemptions (Id int NOT NULL, RedemptionId nvarchar(50), RedemptionItemId nvarchar(50), RedemptionName nvarchar(255), RedemptionAmount numeric, RedemptionDept nvarchar(50), RedemptionSubdept nvarchar(50))";
                command.ExecuteNonQuery();
            }
        }
    }
}

UPDATE 2

I have now changed it to this format:

if (TableExists(connection, "InventoryItems"))
{
    command.CommandText = "DROP TABLE InventoryItems";
    command.ExecuteNonQuery();
}
command.CommandText = "CREATE TABLE InventoryItems (Id nvarchar(50) NOT NULL, PackSize smallint NOT NULL, Description nvarchar(255), DeptDotSubdept float, UnitCost float, UnitList float, UPCCode nvarchar(50), UPCPackSize smallint, CRVId int);";
command.ExecuteNonQuery();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top