Цикл через набор результатов 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
это называется 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
.