Sql Server temporary table disappears

Joe Zack's comment is what helped me understand what's happening here. A very clear and concise explanation. This should be an answer so that it's more visible to people arriving here from a google search.

SqlCommand calls sql with parameters via sp_executesql when there are parameters, which means your temp table gets created inside (and then clean up in) a stored procedure so it's not available to future calls - even when they share the same connection


I think the solution to your problem is to combine the creation of the temp table and selecting from that temp table into one query (see code snippet #3 below). Executing the command twice (as you do in the code in your question) seems to work ok if you are not using command parameters, but fails if they are introduced. I tested a few different approaches and here's what I found.

1) WORKS OK: Use same command object, no command parameters, execute command twice:

using (var conn = new SqlConnection("..."))
{
    conn.Open();
    using (var cmd = conn.CreateCommand())
    {
        const string query = @"
            CREATE TABLE #temp 
                ([ID] INT NOT NULL, [Name] VARCHAR(20) NOT NULL)
            INSERT INTO #temp VALUES(1, 'User 1')
            INSERT INTO #temp VALUES(2, 'User 2')";
        cmd.CommandType = CommandType.Text;
        cmd.CommandText = query;
        cmd.ExecuteNonQuery();

        cmd.CommandText = "SELECT * FROM #temp";
        using (var sda = new SqlDataAdapter(cmd))
        {
            var ds = new DataSet();
            sda.Fill(ds);
            foreach (DataRow row in ds.Tables[0].Rows)
                Console.WriteLine("{0} - {1}", row["ID"], row["Name"]);
        }
    }
}

2) FAILS: Use same command object, command parameters, execute command twice:

using (var conn = new SqlConnection("..."))
{
    conn.Open();
    using (var cmd = conn.CreateCommand())
    {
        const string query = @"
            CREATE TABLE #temp 
                ([ID] INT NOT NULL, [Name] VARCHAR(20) NOT NULL)
            INSERT INTO #temp VALUES(1, @username1)
            INSERT INTO #temp VALUES(2, @username2)
        ";
        cmd.CommandType = CommandType.Text;
        cmd.CommandText = query;
        cmd.Parameters.Add("@username1", SqlDbType.VarChar).Value ="First User";
        cmd.Parameters.Add("@username2", SqlDbType.VarChar).Value ="Second User";
        cmd.ExecuteNonQuery();

        cmd.Parameters.Clear();
        cmd.CommandText = "SELECT * FROM #temp";
        using(var sda = new SqlDataAdapter(cmd))
        {
            var ds = new DataSet();
            sda.Fill(ds);
            foreach(DataRow row in ds.Tables[0].Rows)
                Console.WriteLine("{0} - {1}", row["ID"], row["Name"]);
        }
    }
}

3) WORKS OK: Use same command object, command parameters, execute command once only:

using (var conn = new SqlConnection("..."))
{
    conn.Open();
    using (var cmd = conn.CreateCommand())
    {
        const string query = @"
            CREATE TABLE #temp 
                ([ID] INT NOT NULL, [Name] VARCHAR(20) NOT NULL)
            INSERT INTO #temp VALUES(1, @username1)
            INSERT INTO #temp VALUES(2, @username2)
            SELECT * FROM #temp
        ";
        cmd.CommandType = CommandType.Text;
        cmd.CommandText = query;
        cmd.Parameters.Add("@username1", SqlDbType.VarChar).Value ="First User";
        cmd.Parameters.Add("@username2", SqlDbType.VarChar).Value ="Second User";
        using (var sda = new SqlDataAdapter(cmd))
        {
            var ds = new DataSet();
            sda.Fill(ds);
            foreach (DataRow row in ds.Tables[0].Rows)
                Console.WriteLine("{0} - {1}", row["ID"], row["Name"]);
        }
    }
}

This works. Apparently, if the SqlParameters are in the step that creates the table, the table is not left behind for the next step. Once the table is created, the SqlParameters can be used in a separate step for the INSERT.

        // Create temporary file dropping members from termed groups.
        q = new StringBuilder(500);
        q.Append("create table #ua_param ");
        q.Append("([ID] int not null, fn varchar(50) not null) ");
        sc = new SqlCommand(q.ToString(), db);
        sc.ExecuteNonQuery();

        q = new StringBuilder(500);
        q.Append("insert into #ua_param values(1,@fn1) ");
        q.Append("insert into #ua_param values(2,@fn2) ");
        sc = new SqlCommand(q.ToString(), db);
        sc.Parameters.Add(new SqlParameter("@fn1", sFn));
        sc.Parameters.Add(new SqlParameter("@fn2", sFn2));
        sc.ExecuteNonQuery();

        q = new StringBuilder(500);
        q.Append("select policy_no, name, amt_due, due_date, hic, grp, eff_dt, lis_prem, lis_grp, lis_co_pay_lvl, ");
        q.Append("lep_prem, lapsed, dn_code, [filename], created_dt, created_by ");
        q.Append("into #ua_temp from elig_ua_response inner join #ua_param on [filename] = fn ");
        sc.Parameters.Clear();
        sc.CommandText = q.ToString();
        sc.CommandTimeout = 1800;
        sc.ExecuteNonQuery();

Tags:

C#

Sql Server