在SQL Server 2008中截断/清除表变量


70

是否可以在SQL Server 2008中截断或刷新表变量?

Declare @tableVariable table
(
   id int, 
   value varchar(20)
)


while @start<=@stop

  begin

    insert into @tableVariable(id,value) 
    select id
         , value 
      from xTable 
     where id=@start

   --Use @tableVariable 

   --@tableVariable should be flushed out of 
   -- old values before inserting new  values

    set @start = @start + 1 
  end 

您到底想完成什么?如果您只想再次冲洗它们,为什么还要插入任何东西呢?
LittleBobbyTables-Au Revoir,2014年

2
插入在这里只是象征性的。实际操作要复杂得多,并且涉及许多其他表格
shrekDeep 2014年

1
--Use @tableVariable我认为有一条评论将被用于某些计算中,该计算未包含
在内

1
是的..它将用于一些计算..请不要与USE <somedatabase>混淆
shrekDeep 2014年

Answers:


98

删除所有内容

DELETE FROM @tableVariable

35
更好的答案是“您做不到”,然后解释替代方案。
zanlok

3
这将起作用,但请记住,正如@ Martin%20Smith在下面指出的那样,将记录此删除。如果变量中有很多行,或者此SQL将定期执行,则可能会出现问题。
巴特阅读


11

我想补充到“在技术上采用的”正确的答案DELETE @VariableTable,如果你碰巧也有一个身份场在你的@Table变量(例如i int (1,1)),你想重新使用该表(即使你重新声明它循环),它仍然在范围内,也无法重新设定它的种子。

请参阅:表变量标识列

最好#TempTable在这些情况下使用-然后您可以截断或使用DBCC重新设置种子。
您将通过Truncate获得性能改进,能够创建其他索引。
我认为,经验法则是,如果你曾经打算删除使用一切DELETE @VariableTable,那么你已经推出了代号气味,说,你应该用#TempTableTRUNCATE来代替。


8

表变量不支持TRUNCATE语法-截断它们的唯一方法是隐式地使它们超出范围。

在存储过程中使用时,临时表和表变量都可以缓存,并且以下内容可能会在截断后使用相同的表变量而不是实际删除并创建

CREATE PROC dbo.foo @start INT
AS
  BEGIN
      DECLARE @tableVariable TABLE (
        id    INT,
        value VARCHAR(20))

      INSERT INTO @tableVariable
                  (id,
                   value)
      SELECT id,
             value
      FROM   xTable
      WHERE  id = @start;
  --Use @tableVariable 
  END

GO

WHILE @start <= @stop
  BEGIN
      EXEC dbo.foo @start

      SET @start = @start + 1
  END 

当然,更容易的选择是切换为使用#temp表,因为它TRUNCATE直接支持。

表变量和临时表上的DML都会写入tempdb事务日志。是否值得切换TRUNCATE而不是DELETE取决于所涉及数据的大小。TRUNCATE只会记录页面释放。DELETE将记录实际删除的值。两者之间的另一个区别是,TRUNCATE从表中取消分配了最后一页,而DELETE没有。如果在每次循环迭代中仅插入和删除少量数据,则记录已删除行的开销可能小于不断取消分配和重新分配表中单个页面的开销。

相反,如果您将在每次迭代中插入和删除大量数据,则可能会发现,TRUNCATE这不仅使删除所有行的操作更加有效,而且可以使后续的insert语句受益


你可以使用DELETE FROM @tableVariable,作为公认的答案说明,得到的功能基本等同于TRUNCATE TABLE(除记录-这可能确实是一个问题,如果有在变量很多行,或创建的变量是作为SQL经常运行)。
巴特阅读

@BartRead -优点TRUNCATE有超过DELETE所有行的是事务日志。
马丁·史密斯

可以-我在记录的可接受答案(引用您的答案和评论)中添加了有关记录的注释,因为这可能并不对所有人都显而易见。
巴特阅读

0
--Usage: exec sp_truncateifexists tablename
CREATE PROCEDURE sp_truncateifexists
    @tableVariable nvarchar(200)
AS
BEGIN
    IF EXISTS (
        SELECT 1 
        FROM INFORMATION_SCHEMA.TABLES 
        WHERE TABLE_NAME = @tableVariable )
    BEGIN
        DECLARE @query nvarchar(250)
        SET @query = 'TRUNCATE TABLE ' + @tableVariable 
        EXECUTE (@query)
    END
END
GO

如果以后不需要表,请记住使用 #temp表


-4

我知道这是一个老问题,但是我已经找到一种解决方法。我们有具有数百万行的表,并且由于事务日志空间而不想删除它们。

创建一个过程,并在其中输入要截断的表名,该过程将创建另一个执行trucate的过程,然后删除该过程。

USE [My_Database]
GO
/****** Object:  StoredProcedure [dbo].[ClearOutTable_p1]    Script Date: 23/09/2015 09:03:14 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

-- =============================================
-- Author:      Oraclebhoy
-- Create date: 23/09/2015
-- Description: 
-- 
-- removes the content of the table passed in through the parameter
-- =============================================
create procedure [dbo].[ClearOutTable_p1]
@tablename varchar(max)
as

-- CREATE THE TRUNCATE STATEMENT PASSING IN TABLE VARIABLE
    declare @truncatesql varchar(max)
    set @truncatesql = 'truncate table ' + @tablename

-- IF PROCEDURE EXISTS DROP
    if exists (select name from sys.all_objects where name = 'ClearOutTable_TEMP'and type = 'P')
        begin
            drop procedure [dbo].[ClearOutTable_TEMP]
        end

-- CREATE TEMP PROCEDURE
    exec ('create procedure [dbo].[ClearOutTable_TEMP]
    as
    '+@truncatesql+'')

-- EXECUTE THE PROCEDURE
    exec [dbo].[ClearOutTable_TEMP]

-- DROP THE PROCEDURE
    drop procedure [dbo].[ClearOutTable_TEMP]

希望这可以帮助。


5
为什么需要创建一个单独的过程来执行截断?考虑到您继续创建和删除相同名称的过程,您将如何确保并发性?最重要的是,如何将其用于表变量
GSerg 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.