试图选择...进入 sp_Executedsql 中的临时表 #TempTable。 没有成功插入,但那里写了消息 (受影响的 359 行)表示成功插入? 下面的脚本
DECLARE @Sql NVARCHAR(MAX);
SET @Sql = 'select distinct Coloum1,Coloum2 into #TempTable
from SPCTable with(nolock)
where Convert(varchar(10), Date_Tm, 120) Between @Date_From And @Date_To';
SET @Sql = 'DECLARE @Date_From VARCHAR(10);
DECLARE @Date_To VARCHAR(10);
SET @Date_From = '''+CONVERT(VARCHAR(10),DATEADD(d,DATEDIFF(d,0,GETDATE()),0)-1,120)+''';
SET @Date_To = '''+CONVERT(VARCHAR(10),DATEADD(d,DATEDIFF(d,0,GETDATE()),0)-1,120)+''';
'+ @Sql;
EXECUTE sp_executesql @Sql;
执行后,它会向我返回消息(受影响的 359 行)。 接下来尝试从#TempTable 中选择数据时。
Select * From #TempTable;
它还给我:
Msg 208, Level 16, State 0, Line 2
Invalid object name '#TempTable'.
怀疑它仅在“选择”部分有效。插入不工作。 怎么解决?
【问题讨论】:
【参考方案1】:这个对我有用:
DECLARE @Query as NVARCHAR(MAX);
SET @Query=(SELECT * FROM MyTable) ;
SET @Query=(SELECT 'SELECT * INTO dbo.TempTable FROM ('+@Query +') MAIN;');
EXEC sp_executesql @Query;
SELECT * INTO #TempTable FROM dbo.TempTable;
DROP TABLE dbo.TempTable;
SELECT * FROM #TempTable;
【讨论】:
【参考方案2】:在您的@sql
字符串中,不要插入into #TempTable
。相反,请在没有 INSERT
语句的情况下调用您的 SELECT
语句。
最后,将结果插入到您的临时表中,如下所示:
INSERT INTO @tmpTbl EXEC sp_executesql @sql
另外,如果你使用这种方法,你需要声明临时表
DECLARE @tmpTbl TABLE (
//define columns here...
)
【讨论】:
虽然这个可以工作,但它是不完整的。问题在于,在 OP 的原始示例中,select ... into ... #TempTable ...
实际上会创建临时表,包括动态指定列。为了使您的语句起作用,必须首先创建/声明临时表(或您正在使用的表变量)(以及正确/匹配的列规范)。
啊,是的,我确实忘记提及了。你肯定需要先声明你的临时表。【参考方案3】:
这对我有用
declare @sql nvarchar(max)
create table #temp ( listId int, Name nvarchar(200))
set @sql = 'SELECT top 10 ListId, Name FROM [V12-ListSelector].[dbo].[List]'
insert into #temp
exec sp_executesql @sql
select * from #temp
drop table #temp
【讨论】:
【参考方案4】:declare @sql varchar(1000)
set @sql="select * into #t from table;"
set @sql =@sql + "select * from #t;"
execute SP_EXECUTESQL @sql
【讨论】:
【参考方案5】:要解决此问题,请先使用 CREATE TABLE #TEMPTABLE 命令生成一个空的临时表,然后再运行 sp_executesql。然后使用 sp_executesql 运行 INSERT INTO #TEMPTABLE。这将起作用。这就是我克服这个问题的方法,因为我的所有查询通常都通过 sp_executesql 运行。
【讨论】:
【参考方案6】:本地临时表#table_name
仅在当前会话中可见,全局临时表##table_name
在所有会话中可见。两人都活到他们的会话结束。
sp_executesql
- 创建自己的会话(也许“范围”这个词会更好)所以这就是它发生的原因。
【讨论】:
我认为“范围”这个词会更好。DECLARE @sql NVARCHAR(MAX); SET @sql = 'SELECT @@SPID'; EXECUTE sp_executesql @sql; SELECT @@SPID
谢谢@Michal,我已经想起了这种使用方法。再次感谢
问题是如何解决它。不是为什么它会破裂。我在下面提供了正确答案。 INSERT INTO @tmpTbl EXEC sp_executesql @sql
注意:sp_executesql
不创建自己的会话。相反,它会创建自己的 batch(或执行上下文)。临时表可以被同一会话中的其他批次看到。但是,因为它们在创建它们的批处理退出时被删除,实际上它们只能被从属批处理(即由创建 Temp 表的同一上下文创建的执行上下文)看到。
如果多人尝试运行使用这些全局变量的 proc 会不会出现死锁和其他问题【参考方案7】:
在这种情况下使用全局临时表可能会导致问题,因为该表会在会话之间存在,并且可能会导致异步使用调用代码时出现一些问题。
如果在调用 sp_executesql 之前定义了本地临时表,则可以使用它,例如
CREATE TABLE #tempTable(id int);
sp_executesql 'INSERT INTO #tempTable SELECT myId FROM myTable';
SELECT * FROM #tempTable;
【讨论】:
【参考方案8】:临时表只存在于创建它们的连接中。我希望您无意中在单独的连接上发出选择。您可以通过暂时插入非临时表并查看您的数据是否存在来测试这一点。如果是这种情况,您可以返回原始解决方案,并确保将连接对象传递给您的选择。
【讨论】:
这并不完全正确。当使用 PreparedStatements 之类的东西时,MSSQL 引擎通过存储过程运行它来执行,这意味着任何临时表在存储过程的上下文中都存在,如果你尝试执行一个紧跟从 tempTable 中选择 * 的 PreparedStatement,你将找不到 tempTable。【参考方案9】:您在动态 SQL 中的临时表超出了非动态 SQL 部分的范围。
看这里如何处理这个问题:A bit about sql server's local temp tables
【讨论】: