2017-08-21 38 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