Tabellenvariable in SQL Server 2008 abschneiden / löschen

70

Ist es möglich, eine Tabellenvariable in SQL Server 2008 abzuschneiden oder zu löschen?

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 
shrekDeep
quelle
Was genau versuchst du zu erreichen? Warum überhaupt etwas einfügen, wenn Sie sie nur wieder ausspülen möchten?
LittleBobbyTables - Au Revoir
2
Einfügen ist hier nur symbolisch. Die tatsächliche Bedienung ist viel komplizierter und beinhaltet viele andere Tabellen
shrekDeep
1
Es gibt den Kommentar, von dem --Use @tableVariableich annehme, dass er für einige Berechnungen verwendet wird, die nicht beigefügt sind
Peter
1
Ja .. es wird für einige Berechnungen verwendet .. bitte nicht mit USE <somedatabase> verwechseln
shrekDeep

Antworten:

98

lösche einfach alles

DELETE FROM @tableVariable
Peter
quelle
35
Eine bessere Antwort wäre "Sie können nicht" und dann die Alternative zu erklären.
Zanlok
3
Dies wird funktionieren, aber bedenken Sie, wie @ Martin% 20Smith unten ausgeführt hat, dass diese Löschung protokolliert wird. Wenn die Variable viele Zeilen enthält oder diese SQL regelmäßig ausgeführt wird, kann dies problematisch sein.
Bart Read
40

Nein, Sie können keine TRUNCATETabellenvariable erstellen, da es sich nicht um eine physische Tabelle handelt. Das Löschen wäre schneller. Siehe diese Antwort von Aaron Bertrand .

TTeeple
quelle
4
Für eine große Anzahl von Zeilen TRUNCATEwäre das sicherlich schneller. Das Löschen aus einer Tabellenvariablen wird im tempdbTransaktionsprotokoll protokolliert.
Martin Smith
1
Es kann nicht schneller sein, wenn Sie nicht abschneiden können. Es gibt nur die Löschoption.
Akira Yamamoto
11

Ich würde der " technisch " korrekten Antwort hinzufügen DELETE @VariableTable, wenn Sie zufällig auch ein Identitätsfeld in Ihrer @TableVariablen haben (zi int (1,1) ) und diese Tabelle wiederverwenden möchten (auch wenn Sie sie erneut deklarieren eine Schleife) ist immer noch im Geltungsbereich und es gibt auch keine Möglichkeit, sie erneut zu säen.

Siehe: Spalte mit der Identität der Tabellenvariablen

Es ist am besten zu verwenden #TempTableIn diesen Fällen Dann können Sie DBCC zum erneuten Säen abschneiden oder verwenden.
Mit Truncate erzielen Sie Leistungsverbesserungen und können zusätzliche Indizes erstellen.
Ich denke , die Faustregel, wenn Sie immer alles gehen löschen verwenden DELETE @VariableTable, dann haben Sie einen Code-Geruch eingeführt, der sagt, die Sie verwendet haben sollten #TempTableund TRUNCATEstattdessen.

MikeTeeVee
quelle
8

Tabellenvariablen werden nicht unterstützt TRUNCATE Syntax. Die einzige Möglichkeit, sie abzuschneiden, besteht darin, sie implizit aus dem Gültigkeitsbereich fallen zu lassen.

Sowohl temporäre Tabellen als auch Tabellenvariablen können zwischengespeichert werden, wenn sie in gespeicherten Prozeduren verwendet werden. Im Folgenden wird möglicherweise dieselbe Tabellenvariable nach dem Abschneiden verwendet, anstatt sie tatsächlich zu löschen und zu erstellen

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 

Eine weitaus einfachere Alternative wäre natürlich die Umstellung auf a #temp Tabelle zu verwenden, da dies TRUNCATEdirekt unterstützt .

DML für Tabellenvariablen und temporäre Tabellen schreibt in das tempdbTransaktionsprotokoll. Unabhängig davon , ob es lohnt Umschaltung TRUNCATEstatt , DELETEhängt von der Größe der betreffenden Daten. TRUNCATEprotokolliert nur die Freigabe der Seite. DELETEprotokolliert die tatsächlich gelöschten Werte. Ein weiterer Unterschied zwischen den beiden besteht darin, dass die TRUNCATEZuordnung der letzten Seite aus der Tabelle aufgehoben wird und DELETEdies nicht der Fall ist. Wenn in jeder Schleifeniteration nur eine kleine Datenmenge eingefügt und gelöscht wird, kann der Aufwand für die Protokollierung der gelöschten Zeilen geringer sein als der Aufwand für die ständige Freigabe und Neuzuweisung der einzelnen Seite in der Tabelle.

Wenn Sie dagegen bei jeder Iteration große Datenmengen einfügen und löschen, werden Sie möglicherweise feststellen, dass TRUNCATEdas Löschen aller Zeilen nicht nur effizienter ist, sondern auch der nachfolgenden Einfügeanweisung zugute kommt .

Martin Smith
quelle
Sie können einfach DELETE FROM @tableVariable, wie in der akzeptierten Antwort beschrieben, verwenden, um eine Funktionalität zu erhalten, die im Wesentlichen der entspricht TRUNCATE TABLE(mit Ausnahme der Protokollierung - dies könnte sicherlich ein Problem sein, wenn die Variable viele Zeilen enthält oder die SQL, die die Variable erstellt hat, vorhanden ist sehr oft laufen).
Bart Read
@BartRead - Der Vorteil TRUNCATEgegenüber DELETEallen Zeilen ist die Transaktionsprotokollierung.
Martin Smith
Sicher - Ich habe der akzeptierten Antwort (unter Bezugnahme auf Ihre Antwort und Kommentare) einen Hinweis zur Protokollierung hinzugefügt, da dies möglicherweise nicht für alle offensichtlich ist.
Bart Read
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

Denken Sie daran, # temp-Tabellen zu verwenden , wenn Sie die Tabellen später nicht benötigen.

Daniel Holth
quelle
-4

Ich weiß, dass dies eine alte Frage ist, aber ich habe einen Weg gefunden, dies zu tun. Wir hatten Tabellen mit Millionen von Zeilen und wollten sie aufgrund des Transaktionsprotokollbereichs nicht löschen.

Erstellen Sie eine Prozedur, die Sie in dem Tabellennamen übergeben, den Sie abschneiden möchten. Die Prozedur erstellt eine andere Prozedur, die die Trukate ausführt, und löscht dann die Prozeduren.

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]

Hoffe das hilft.

oraclebhoy
quelle
5
Warum müssen Sie eine separate Prozedur erstellen, um ein Abschneiden auszuführen? Wie stellen Sie die Parallelität sicher, wenn Sie die Prozedur mit demselben Namen weiterhin erstellen und löschen? Und vor allem, wie werden Sie das für Tabellenvariablen verwenden ?
GSerg