SQL Server How to output one table result from multiple results with a WHILE query

元气小坏坏 提交于 2019-11-30 23:19:02

You are wasting your time and energy following such bad advice. If you absolutely must (extra emphasis on the must) take a row-by-row approach (CURSOR or WHILE loop), then you are better off with a CURSOR. It is a built-in construct that is more efficient, and less error-prone. You just need to use the right options, such as making it STATIC, LOCAL, READ_ONLY, and FORWARD_ONLY. You don't need STATIC if the cursor query is only hitting temporary tables and/or table variables.

People will argue with this and say that "you must avoid cursors at all cost!", but they haven't done the tests to see that such a popular notion is really just a myth. And if they have done tests that appear to confirm it, then they haven't set the appropriate options, mostly STATIC, which dumps the result of the cursor query into a temp table. Without this option, fetching new rows will re-check the base tables to make sure that they still exist, and that is where the performance hit is (the I/O plus the locking). And that is also why you typically don't need the STATIC option when querying only temporary tables and/or table variables. What do I mean by "re-checking"? Just look at the documentation for @@FETCH_STATUS. The return values don't just cover "success" (0) and "no more rows" (-1): there is a return value, (-2), that means "The row fetched is missing".

SET NOCOUNT ON;
DECLARE @Id INT,
        @Name sysname,
        @Type VARCHAR(5);

--  the Table Variable replaces #Temp2 in the original query
DECLARE @Output TABLE (Id INT NOT NULL, Name sysname, [Type] VARCHAR(5));

-- the CURSOR replaces #Temp in the original query
DECLARE crs CURSOR STATIC LOCAL READ_ONLY FORWARD_ONLY
FOR  SELECT [object_id], name, [type]
     FROM   sys.objects -- dbo.sysobjects for SQL 2000 -- ATable in the original query
    ORDER BY [object_id] ASC;

OPEN crs;

FETCH NEXT
FROM  crs
INTO  @Id, @Name, @Type;

WHILE (@@FETCH_STATUS = 0)
BEGIN
    INSERT INTO @Output (Id, Name, [Type])
    VALUES (@Id, @Name, @Type);

    -- do some processing..

    FETCH NEXT -- replaces the DELETE and re-SELECT in the original query
    FROM  crs
    INTO  @Id, @Name, @Type;
END;

CLOSE crs;
DEALLOCATE crs;

SELECT Id, Name, [Type]
FROM   @Output;

UPDATE

Given the iteration is being done over a query that splits a CSV of INTs, the resulting query would look similar to the following:

SET NOCOUNT ON;

DECLARE @String VARCHAR(1000);
SELECT @String = str FROM [Table]; --with the 1234,1432,1235

DECLARE @Id INT,
        @Name NVARCHAR(50),
        @Age  TINYINT;

DECLARE @Output TABLE (Id INT NOT NULL, Name NVARCHAR(50), Age TINYINT);

DECLARE crs CURSOR STATIC LOCAL READ_ONLY FORWARD_ONLY
FOR  SELECT SUBSTRING(',' + @String + ',', Number + 1,
     CHARINDEX(',', ',' + @String + ',', Number + 1) - Number -1) AS [ID]
     FROM master..spt_values
     WHERE Type = 'P'
     AND Number <= LEN(',' + @String + ',') - 1
     AND SUBSTRING(',' + @String + ',', Number, 1) = ',';

OPEN crs;

FETCH NEXT
FROM  crs
INTO  @Id;

WHILE (@@FETCH_STATUS = 0)
BEGIN
    -- do some processing..
    -- Logic to set value of @Name
    -- Logic to set value of @Age

    INSERT INTO @Output (Id, Name, Age)
    VALUES (@Id, @Name, @Age);

    FETCH NEXT
    FROM  crs
    INTO  @Id;
END;

CLOSE crs;
DEALLOCATE crs;

SELECT Id, Name, Age
FROM   @Output;

your query has syntax error but I tried below query and worked fine

-- this is only to populate my data table
Select object_id Id, name Into #Temp From sys.tables

select * into #temp2 from #Temp where 1=2

Declare @Id int

WHILE EXISTS(SELECT * FROM #Temp)
Begin
    Select Top 1 @Id = Id
    From #Temp
    ORDER BY Id -- this order is important

    -- use insert...into, NOT select...into
    insert into #temp2 
    select * 
    from #Temp
    where Id = @Id

    Delete #Temp Where Id = @Id
End

BTW, you can not have SELECT...INTO inside a loop, as the 2nd iteration will raise error. You need to create #temp2, out side the loop and use INSERT...INTO instead of SELECT...INTO

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!