Цикл через набор результатов SELECT в SQL

Я даже не уверен, как сформулировать этот вопрос, но здесь идет. Мне нужно иметь возможность перебирать результирующий набор в одном сценарии SQL и использовать результаты в большем количестве SQL.

begin
SELECT (SELECT ColumnA, ColumnB from SomeTable) as x

loop through x(
    INSERT ColumnA into TableA
    INSERT ColumnB into TableB
    )
end

но я забыл точный способ сделать это. Я знаю, что я делал это раньше на предыдущей должности, но я не могу найти код для этого в моих файлах из этой компании.

очевидно, что это очень грубый и простой пример и я планирую сделать намного больше с результирующий набор, но я просто привел это в качестве примера.


EDIT: вот более близкий пример того, что я хочу сделать, если это поможет.

begin
    while(select columnA, columnB, columnC, columnD from myTable) as x

    begin
        INSERT columnA, columnB into TableA

        (get newly created ID of TableA - but that's a separate question involving @@IDENTITY)

        INSERT NewID, columnC, columnD into TableB
    end loop
end

4 ответов


обычный способ обработки получения идентификатора в установленном порядке - через OUTPUT статья:

INSERT INTO TableA (ColumnA, ColumnB)
OUTPUT inserted.Id, inserted.ColumnA, inserted.ColumnB
SELECT  ColumnA, ColumnB
FROM    MyTable;

проблема здесь в том, что в идеале вы хотели бы сделать следующее:

INSERT INTO TableA (ColumnA, ColumnB)
OUTPUT inserted.Id, MyTable.ColumnC, inserted.ColumnD 
    INTO TableB (AID, ColumnC, ColumnD)
SELECT  ColumnA, ColumnB
FROM    MyTable;

проблема в том, что вы не можете ссылаться на исходную таблицу в выходных данных, только на цель. К счастью, для этого есть обходной путь с помощью MERGE, так как это позволяет использовать ссылку как на вставленную таблицу резидентной памяти, так и на источник таблицы в предложении output, если вы используете MERGE при условии, что никогда не будет истинным, вы можете вывести все необходимые столбцы:

WITH x AS
(   SELECT  ColumnA, ColumnB, ColumnC, ColumnD
    FROM    MyTable
)
MERGE INTO TableA AS a
USING x
    ON 1 = 0 -- USE A CLAUSE THAT WILL NEVER BE TRUE
WHEN NOT MATCHED THEN 
    INSERT (ColumnA, ColumnB)
    VALUES (x.ColumnA, x.ColumnB)
OUTPUT inserted.ID, x.ColumnC, x.ColumnD INTO TableB (NewID, ColumnC, ColumnD);

проблема с этим методом заключается в том, что SQL Server не позволяет вставлять любую сторону отношения внешнего ключа, поэтому, если tableB.NewID ссылается на таблицу.ID тогда вышеперечисленное не удастся. Чтобы обойти это, вам нужно будет вывести во временную таблицу, а затем вставить временную таблицу в Таблицы tableb:

CREATE TABLE #Temp (AID INT, ColumnC INT, ColumnD INT);
WITH x AS
(   SELECT  ColumnA, ColumnB, ColumnC, ColumnD
    FROM    MyTable
)
MERGE INTO TableA AS a
USING x
    ON 1 = 0 -- USE A CLAUSE THAT WILL NEVER BE TRUE
WHEN NOT MATCHED THEN 
    INSERT (ColumnA, ColumnB)
    VALUES (x.ColumnA, x.ColumnB)
OUTPUT inserted.ID, x.ColumnC, x.ColumnD INTO #Temp (AID, ColumnC, ColumnD);

INSERT TableB (AID, ColumnC, ColumnD)
SELECT AID, ColumnC, ColumnD
FROM #Temp;

пример на SQL Fiddle


на SQL это называется CURSORS. Основная структура CURSOR - это:

 DECLARE @ColumnA INT, @ColumnB INT

 DECLARE CurName CURSOR FAST_FORWARD READ_ONLY
 FOR
    SELECT  ColumnA, ColumnB
    FROM    SomeTable

 OPEN CurName

 FETCH NEXT FROM CurName INTO @ColumnA, @ColumnB

 WHILE @@FETCH_STATUS = 0
    BEGIN

        INSERT  INTO TableA( ColumnA )
        VALUES  ( @ColumnA )
        INSERT  INTO TableB( ColumnB )
        VALUES  ( @ColumnB )

        FETCH NEXT FROM CurName INTO @ColumnA, @ColumnB

    END

 CLOSE CurName
 DEALLOCATE CurName

другой способ итеративного решения -WHILE петли. Но для этого вы должны иметь уникальный столбец идентификаторов в таблице. Например

DECLARE @id INT

SELECT TOP 1 @id  =  id FROM dbo.Orders ORDER BY ID

WHILE @id IS NOT NULL
BEGIN

  PRINT @id

  SELECT TOP 1 @id  =  id FROM dbo.Orders WHERE ID > @id ORDER BY ID
  IF @@ROWCOUNT = 0
  BREAK

END

но обратите внимание, что вы должны избегать использования CURSORS Если есть альтернативный не итерационный способ выполнения той же работы. Но конечно есть ситуации, когда вы не можете избежать CURSORs


Не используйте курсор, поскольку это не хорошо, когда дело доходит до производительности.

попробуйте эту ссылку: http://support2.microsoft.com/kb/111401

вы должны использовать ROW_NUMBER () и заполнить данные в таблицу temporay-переменную или глобальную таблицу.


если вы только вставляете данные из одной таблицы в другую, вы можете использовать этот подход:

insert into TableA (ColumnA, ColumnB, myTableID)
select (ColumnA, ColumnB, myTableID) from myTable

insert into TableB (ColumnC, ColumnD, myTableID)
select m.ColumnC, m.ColumnD, a.TableAid
from myTable m
join TableA a
    on m.myTableID = a.myTableID

Edit:

вы можете добавить столбец в TableA внешнего ключа myTable. Это поможет вам получить ID TableA на TableB.