循环遍历SQL中的SELECT结果集

时间:2015-02-24 17:17:51

标签: sql sql-server sql-server-2008 tsql

我甚至不确定怎么说这个问题但是这里有。我需要能够在同一个SQL脚本中循环遍历结果集,并在更多SQL中使用结果。

例如

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

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

但我忘了这样做的确切方法。我知道我之前在以前的职位上已经完成了这项工作,但我无法在该公司的文件中找到该代码。

显然,这是一个非常粗略和基本的例子,我计划用结果集做更多的事情,但我只是以此为例。


编辑:以下是我希望做的更接近的例子,以防万一。

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 个答案:

答案 0 :(得分:15)

SQL中,它被称为CURSORSCURSOR的基本结构是:

 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

答案 1 :(得分:5)

以基于集合的方式处理身份的常用方法是通过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;

问题是您无法在OUTPUT中引用源表,只能引用目标。幸运的是,使用MERGE可以解决此问题,因为如果在永远不会使用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); ,则允许您使用引用内存插入表和输出子句中的源表。是的,你可以输出你需要的所有列:

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 Server不允许您插入外键关系的任何一侧,因此如果tableB.NewID引用tableA.ID,则上述操作将失败。要解决此问题,您需要输出到临时表,然后将临时表插入TableB:

{{1}}

<强> Example on SQL Fiddle

答案 2 :(得分:0)

不要使用光标,因为它在性能方面不好。

试试这个链接: http://support2.microsoft.com/kb/111401

您应该使用ROW_NUMBER()并将数据填充到临时表 - 变量表或全局表中。

答案 3 :(得分:0)

如果您只是将数据从一个表插入另一个表,则可以使用以下方法:

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

修改

您可以在TableA的外键myTable中添加一列。这有助于您在TableA中获得TableB的ID。