替代此Cursor SQL

时间:2017-08-21 18:12:44

标签: sql-server tsql cursor

如何在没有光标的情况下执行此操作:

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表,这个表有一个状态列,该产品的最后状态。我有另一个表PRODUCT_HISTORY,它在产品上更改了所有信息,包括旧状态。对于每个产品,我需要获取最后一个状态并将其插入到产品表的新字段中。像这样:

sample

1 个答案:

答案 0 :(得分: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