17 Stimmen

Einfügeanweisung x-mal ausführen

Ich habe zwei Tabellen. Eine Tabelle A hat n Datenzeilen und die andere Tabelle B leer ist. Ich möchte insert n Zeilen in Tabelle B 1 Zeile für jede Zeile der Tabelle A . Tabelle B werden einige Felder aus der Tabelle A enthalten, einschließlich eines Fremdschlüssels aus der Tabelle A .

Am Ende möchte ich eine Zeile in B für jede Zeile in A . Hierfür habe ich verwendet:

INSERT INTO B(Col1
             ,Col2
             ,Col3
             ,Col4
             ,Col5
             );
SELECT 100
      ,25 
      ,'ABC'
      ,1
      ,A.ID
FROM Auctions A

Jetzt habe ich diesen Code in eine gespeicherte Prozedur eingefügt, und diese SP nimmt eine int param genannt NumInserts .

Ich möchte einfügen n * NumInserts Reihen. Wenn also n gleich 10 und NumInserts gleich 5 ist, möchte ich diesen Code 5 * 10 (50) Mal ausführen.

Mit anderen Worten, für jede Zeile in table A Ich möchte insert 5 Zeilen in table B . Wie würde ich das machen?

22voto

Clarice Bouwer Punkte 3211
create procedure insert_into_b
    @numInserts int
as
begin
    while @numInserts > 0
    begin
        insert into b (id)
        select id from a
        set @numInserts = @numInserts - 1
    end
end

exec insert_into_b 2

11voto

Cristian Lupascu Punkte 36824

Dies ist ein Hack und ich würde nicht empfehlen, ihn in der Produktion oder bei großen Datenmengen zu verwenden. Bei der Entwicklung von Quick-and-Dirty-Szenarien fand ich es jedoch oft nützlich:

Utilice GO \[count\] um einen Stapel von Befehlen eine bestimmte Anzahl von Malen auszuführen.

Konkret, wenn Sie eine gespeicherte Prozedur namens InsertAIntoB können Sie dies in Management Studio ausführen:

exec InsertAIntoB
GO 10

(ersetzen 10 mit dem Wert von NumInserts)

10voto

Cᴏʀʏ Punkte 101076

Ich ziehe es vor, Schleifen zu vermeiden, wenn ich kann, nur damit ich nicht eine leicht zu unterbrechende und etwas hässliche Schleifenstruktur in meiner gespeicherten Prozedur pflegen muss.

Sie können dies leicht mit einer Numbers Tabelle, die CROSS APPLY Anweisung, und Ihre bestehende INSERT Erklärung.

Ihre Zahlentabelle würde dann wie folgt aussehen:

Number
======
0
1
2
...

Ihre SQL-Anweisung wird einfach:

INSERT INTO B 
(
    [Col1]
    ,[Col2]
    ,[Col3]
    ,[Col4]
    ,[Col5]
)
SELECT 
    100 
    ,25
    ,'ABC'
    ,1
    ,a.ID
FROM 
    Auctions a
CROSS APPLY
    Numbers n
WHERE
    n.Number BETWEEN 1 AND @NumInserts

Zahlentabellen können nützlich sein, wenn man sie richtig einsetzt. Wenn Sie mit ihnen nicht vertraut sind, finden Sie hier einige Ressourcen und einige Vor- und Nachteile:

Vielleicht ist diese Lösung zu viel des Guten, wenn @NumInserts wird immer eine recht kleine Zahl sein, aber wenn Sie schon einen Zahlentisch haben, können Sie ihn auch gleich nutzen!

UPDATE :

Hier ist eine schnelle und schmutzige Methode, um eine Zahlentabelle von 0 bis 65.535 aufzufüllen:

CREATE TABLE Numbers
(
    Number INT NOT NULL,
    CONSTRAINT PK_Numbers 
        PRIMARY KEY CLUSTERED (Number)
        WITH FILLFACTOR = 100
)
GO

INSERT INTO Numbers
SELECT
    (a.Number * 256) + b.Number AS Number
FROM 
(
    SELECT number
    FROM master..spt_values
    WHERE 
        type = 'P'
        AND number <= 255
) a (Number),
(
    SELECT number
    FROM master..spt_values
    WHERE 
        type = 'P'
        AND number <= 255
) b (Number)
GO

<strong>Kredit: </strong><a href="http://dataeducation.com/you-require-a-numbers-table/" rel="nofollow noreferrer">http://dataeducation.com/you-require-a-numbers-table/</a>

3voto

Charles Bretana Punkte 137391
 Create procedure DoitNTimes 
 @N integer = 1
 As
 Set NoCount On

    While @N > 0 Begin
       Insert B (Col1, Col2, Col3, Col4, Col5)
       Select 100, 25, 'ABC', 1, A.ID
       From Auctions A
       -- -----------------------------------
       Set @N -= 1
    End

Wenn Sie SQL Server 2005 oder früher verwenden, ersetzen Sie die Set @N -= 1' with Set @N = @N-1`

und wenn Sie eine Schleife mit T-SQL-Variablen wirklich vermeiden wollen, dann verwenden Sie eine CTE und keine plattenbasierte Tabelle:

 Create procedure DoitNTimes 
 @N integer = 1
 As
 Set NoCount On

     With nums(num) As
       (Select @N Union All
        Select num - 1
        From nums
        Where num > 1)
     Insert B (Col1, Col2, Col3, Col4, Col5)
     Select 100, 25, 'ABC', 1, A.ID
     From Auctions A Full Join nums
     Option(MaxRecursion 10000) 

aber natürlich ist auch dies eine Schleife, genau wie jede andere Lösung für dieses Problem.

1voto

Jay13 Punkte 730

Sehr späte Antwort, aber es ist nicht nötig, eine Schleife zu machen, und es ist ein bisschen einfacher als Coreys gute Antwort;

DECLARE @n int = 10;
INSERT INTO B(Col1,Col2,Col3,Col4,Col5);
SELECT 100,25,'ABC',1,A.ID
FROM Auctions A
JOIN (SELECT TOP(@n) 1 [junk] FROM sys.all_objects) as copies ON 1 = 1

Sie können jede beliebige Tabelle in der Verknüpfung verwenden, solange sie die benötigte Anzahl von Zeilen enthält. Sie könnten auch "1 [junk]" in "ROW_NUMBER() OVER(ORDER BY object_id) [copyno]" ändern, wenn Sie irgendwo in der Insert-Tabelle eine Kopiennummer haben wollen.

Hoffentlich erspart das jemandem ein wenig Arbeit...

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X