我正在尝试从select语句创建临时表,以便我可以从临时表中获取架构信息。
我可以使用以下代码在SQL Server中实现此目的:
//This creates the temp table
SELECT location.id, location.name into #URM_TEMP_TABLE from location
//This retrieves column information from the temp table
SELECT * FROM tempdb.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME like '#U%'
如果我在c#中运行代码,那么:
using (CONN = new SqlConnection(Settings.Default.UltrapartnerDBConnectionString))
{
var commandText = ReportToDisplay.ReportQuery.ToLower().Replace("from", "into #URM_TEMP_TABLE from");
using (SqlCommand command = CONN.CreateCommand())
{
//Create temp table
CONN.Open();
command.CommandText = commandText;
int retVal = command.ExecuteNonQuery();
CONN.Close();
//get column data from temp table
command.CommandText = "SELECT * FROM TEMPDB.INFORMATION_SCHEMA.Columns WHERE TABLE_NAME like '#U%'";
CONN.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
ColumnsForReport.Add(new ListBoxCheckBoxItemModel
{
Name = reader["COLUMN_NAME"].ToString(),
DataType = reader["DATA_TYPE"].ToString(),
IsSelected = false,
RVMCommandModel = this
});
}
}
CONN.Close();
//drop table
command.CommandText = "DROP TABLE #URM_TEMP_TABLE";
CONN.Open();
command.ExecuteNonQuery();
CONN.Close();
}
}
一切正常,直到它到达drop语句:不能删除表'#URM_TEMP_TABLE'
因此ExecuteNonQuery返回2547 - 这是临时表应该包含在其中的行数。但是,似乎实际上并没有使用此表创建表。 ExecuteNonQuery是正确的调用方法吗?
答案 0 :(得分:5)
临时表仅在当前会话的范围内,在您发布的代码中,您正在打开连接,创建临时表,关闭连接。
然后打开另一个连接(新会话)并尝试删除不在该会话范围内的表。
您需要在同一连接中删除临时表,或者可能使其成为全局临时表(##) - 尽管在这种情况下具有两个单独的连接,但全局临时表仍将超出范围。 / p>
此外,正如评论中指出的那样,您的临时表将自动清理 - 但如果您确实想要删除它们,则必须从创建它们的会话中执行此操作。
来自另一个SO线程的编辑:
Global temporary tables in SQL Server
全局临时表的运行方式与本地临时表非常相似;他们 在tempdb中创建并导致更少的锁定和日志记录 永久表。但是,它们对所有会话都可见,直到 创建会话超出范围(全局##临时表不是 更长时间被其他会议引用)。如果两个不同的会话 尝试上面的代码,如果第一个仍然有效,第二个将 收到以下信息:
服务器:消息2714,级别16,状态6,行1已经有一个对象 在数据库中命名为“## people”。
我还没有看到使用全局## temp的有效理由 表。如果数据需要持久化到多个用户,那么它就会产生 使用永久桌子至少对我来说更有意义。您可以 通过创建一个全局##临时表使其更加永久 一个自动启动程序,但我仍然不知道这是怎么回事 比永久桌更有利。有了永久桌子,你可以 否认权限;你不能拒绝来自全球##临时表的用户。
看起来全局临时表仍然超出范围......它们在一般的IMO中使用起来很糟糕。您可以将该表放在同一会话中或重新考虑您的解决方案吗?