Sql Server临时表消失

我正在创建一个临时表#ua_temp,它是常规表的子集。 我没有收到错误,但是当我在第二步尝试从#ua_temp中选择时,它没有找到。 如果删除#,则会创建名为ua_temp的表。

我使用了与其他地方的SELECT INTO创建表完全相同的技术。 它运行正常,所以我不认为它与数据库设置有任何关系。 有谁能看到这个问题?

// Create temporary table q = new StringBuilder(200); 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 "); q.Append("where [filename] = @fn1 or [filename] = @fn2 "); sc = new SqlCommand(q.ToString(), db); sc.Parameters.Add(new SqlParameter("@fn1", sFn)); sc.Parameters.Add(new SqlParameter("@fn2", sFn2)); int r = sc.ExecuteNonQuery(); MessageBox.Show(r.ToString() + " rows"); // Rosters q = new StringBuilder(200); q.Append("select policy_no,name,amt_due,due_date,hic,grp,eff_dt,"); q.Append("lis_prem,lis_grp,lis_co_pay_lvl,lep_prem,lapsed,dn_code,[filename] "); q.Append("from #ua_temp where (lis_prem > 0.00 or lep_prem > 0.00) "); q.Append("and [filename] = @fn order by name"); sc.CommandText = q.ToString(); sc.Parameters.Clear(); sc.Parameters.Add(new SqlParameter("@fn", sFn)); sda = new SqlDataAdapter(sc); sda.Fill(ds, "LIS LEP Roster"); 

回答一些显而易见的问题:使用源表elig_ua_response,该程序运行正常。 引入临时表的原因是我想删除此特定报告的一些行。 我在测试时在列[filename]周围放置了括号,以确保它不是关键字问题。 如果用#elig_ua_response替换#ua_temp,第二个SELECT工作正常。 我为临时表尝试了不同的名称。 显示行数的MessageBox仅用于调试目的; 它不会影响问题。

我认为你的问题的解决方案是结合临时表的创建和从临时表中选择一个查询(参见下面的代码片段#3)。 如果您没有使用命令参数,则执行命令两次(就像您在问题中的代码中所做的那样)似乎工作正常,但如果引入它们则会失败。 我测试了一些不同的方法,这是我发现的。

1)工作正常 :使用相同的命令对象,无命令参数,执行命令两次:

 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 :使用相同的命令对象,命令参数,执行命令两次:

 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)工作正常 :使用相同的命令对象,命令参数,仅执行一次命令:

 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"]); } } } 

这很有效。 显然,如果SqlParameters位于创建表的步骤中,则表格不会留下用于下一步。 创建表后,可以在INSERT的单独步骤中使用SqlParameters。

  // 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(); 

因为临时表就是这样。 临时。 您可以考虑在存储过程中执行操作。

#TEMP表只能在同一会话或SPID中访问。 因此,如果要重用它,则需要重用用于生成它的连接。

我有同样的问题。 我尝试了SeaDrive解决方案并且它可以工作,但是我的测试让我相信查询执行“刷新”“ADO.NET/SQLDriver”和MS SQL Server之间的某些东西。

因此,您需要隔离“CREATE TABLE”语句并将其提交到数据库,然后再将其与“INSERT INTO”一起使用。 除非您可以放弃参数,否则在一个唯一语句中加入CREATE和INSERT的组合命令不起作用。

Joe Zack的评论是帮助我理解这里发生的事情的原因。 一个非常清晰简洁的解释。 这应该是一个答案,以便从谷歌搜索到达这里的人更容易看到它。

当有参数时,SqlCommand通过sp_executesql调用带有参数的sql,这意味着你的临时表在内部创建(然后清理)存储过程,以便将来的调用无法使用 – 即使它们共享相同的连接

除了按照@Daniel A White的建议将其滚动到存储过程之外,您可以查看BOL文章并搜索全局临时表 。 还简要介绍了临时表 。 这两种方法都应该使临时表保持活跃状态​​。

使用存储过程对于这种事情是有意义的。

如果由于某种原因不可行,那么确保使用与临时表创建相同的连接来创建临时表,否则临时表将不可见。 (如果您正在使用连接池,可能会随机出现此问题。)或者,使用真实的物理表甚至是全局临时表(## global_tmp vs #local_tmp),但在任何一种情况下,您都需要设计一个方案/协议,使多个进程不会尝试创建/删除/写入该表。

同样,我会强调,如果可能的话,存储过程将是一条好路线。