2017-08-21 67 views
-1

我怎樣才能做到這一點沒有光標:替代這個遊標SQL

SET NOCOUNT ON; 
DECLARE @VAR_A BIGINT, @VAR_B TINYINT; 

DECLARE _CURSOR CURSOR FOR 
SELECT A, B FROM MY_TABLE 

OPEN _CURSOR 
FETCH NEXT FROM _CURSOR 
INTO @VAR_A, @VAR_B 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    SELECT TOP 2 A, B, C, ROW_NUMBER() OVER (ORDER BY A DESC) AS ROW_NUM 
    INTO #TMP FROM MY_TABLE_2 
    WHERE A = @VAR_A AND X = 0 ORDER BY A DESC 
    IF ((SELECT COUNT(*) FROM #TMP) = 1) BEGIN 
     UPDATE MY_TABLE 
      SET Y = (SELECT B FROM #TMP WHERE ROW_NUM = 1) 
     WHERE A = @VAR_A 
    END ELSE IF (@VAR_B = 7) BEGIN 
     UPDATE MY_TABLE 
     SET Y = (SELECT B FROM #TMP WHERE ROW_NUM = 2), 
      Z = (SELECT C FROM #TMP WHERE ROW_NUM = 2) 
     WHERE A = @VAR_A 
    END ELSE BEGIN 
     UPDATE MY_TABLE 
     SET Y = (SELECT B FROM #TMP WHERE ROW_NUM = 2) 
     WHERE A = @VAR_A 
    END 

    DROP TABLE #TMP 

    FETCH NEXT FROM _CURSOR 
    INTO @VAR_A, @VAR_B 
END 
CLOSE _CURSOR; 
DEALLOCATE _CURSOR; 

我有一個產品表,這個表有一個狀態欄,該產品的最新狀態。我有另一張表,即PRODUCT_HISTORY,其中包含產品更改的所有信息,包括舊的狀態。對於每種產品,我需要獲得最後的狀態並將其插入產品表上的新字段。就像這樣:

sample

+5

而是希望我們解剖這個光標去了解它的意圖,爲什麼不解釋它做了什麼以及你試圖用這個光標來回答你的整體問題是什麼?由於它是自引用的,因此可能會自行加入......也會明智地標記各自的RDMS(版本)。 – scsimon

+0

我有一個PRODUCT表,該表具有狀態列,即產品的最後一個狀態。我有另一張表,即PRODUCT_HISTORY,其中包含產品更改的所有信息,包括舊的狀態。對於每種產品,我需要獲得最後的狀態並將其插入產品表上的新字段。 –

+0

然後不,你不需要光標。然而,樣本數據和預期的輸出在這裏是需要的... – scsimon

回答

0

這應該做的伎倆......

IF OBJECT_ID('tempdb..#Product', 'U') IS NOT NULL 
DROP TABLE #Product; 

CREATE TABLE #Product (
    Id INT NOT NULL PRIMARY KEY CLUSTERED, 
    [Description] VARCHAR(20) NOT NULL, 
    [Status] INT NOT NULL, 
    OlderStatus INT NULL 
    ); 

INSERT #Product (Id, [Description], [Status]) VALUES 
    (1, 'Product A', 5), 
    (2, 'Product B', 7), 
    (3, 'Product C', 4), 
    (4, 'Product D', 3), 
    (5, 'Product E', 0); 

IF OBJECT_ID('tempdb..#ProductHistory', 'U') IS NOT NULL 
DROP TABLE #ProductHistory; 

CREATE TABLE #ProductHistory (
    Id INT NOT NULL PRIMARY KEY CLUSTERED, 
    [Date] DATE NOT NULL, 
    Status INT NOT NULL, 
    ProductId INT NOT NULL 
    ); 

INSERT #ProductHistory (Id, [Date], [Status], ProductId) VALUES 
    (1, '2017-01-01', 0, 1), 
    (2, '2017-01-02', 1, 1), 
    (3, '2017-01-03', 5, 1), 
    (4, '2017-01-04', 0, 2), 
    (5, '2017-01-05', 1, 2), 
    (6, '2017-01-06', 5, 2), 
    (7, '2017-01-07', 7, 2), 
    (8, '2017-01-08', 0, 3), 
    (9, '2017-01-09', 4, 3), 
    (10, '2017-01-10', 0, 4), 
    (11, '2017-01-11', 3, 4), 
    (12, '2017-01-12', 0, 5); 

--=================================================== 

-- the actual solution... 
WITH 
    cte_PH AS (
     SELECT 
      ph.Id, ph.Date, ph.Status, ph.ProductId, 
      RN = ROW_NUMBER() OVER (PARTITION BY ph.ProductId ORDER BY ph.Date DESC) 
     FROM 
      #ProductHistory ph 
     ) 
UPDATE p SET 
    p.OlderStatus = ISNULL(ph.Status, 0) 
FROM 
    #Product p 
    LEFT JOIN cte_PH ph 
     ON p.id = ph.ProductId 
     AND ph.RN = 2; 

---------------------------------------- 

SELECT * FROM #Product p; 

結果...

Id   Description   Status  OlderStatus 
----------- -------------------- ----------- ----------- 
1   Product A   5   1 
2   Product B   7   5 
3   Product C   4   0 
4   Product D   3   0 
5   Product E   0   0