SQL Server存储过程:UPDATE具有最低值,否则INSERT如果已经有值

时间:2017-08-17 22:17:16

标签: sql sql-server sql-server-2008 procedure

希望一次迁移20K行左右。已经离SQL超过10年并且在苦苦挣扎。

我可能会完全错误。需要使用Table1.Value2中的最低值更新Table2.Value1,除非已经Value2。如果是后者,我需要插入一行,其值为Table1.Value1

Table1.Value1是该行的每个ID的最低值。 Value2需要是次低的。

当前表1:

ID1, 123, [empty]
ID4, 111, [empty]

当前表2:

ID1, 224
ID1, 331
ID4, 210
ID4, 551

表1 - 所需状态:

ID1, 123, 224
ID1, 331, [empty]
ID4, 111, 210
ID4, 551, [empty]

表2 - 所需状态:

[empty]

这是我尝试的内容,更新部分正常运行。插入从不起作用。我想我把自己编成了一个角落。

CREATE PROCEDURE dbo.Broken
AS
    --DECLARE VARIABLES
    DECLARE @ID INT,
            @Value1 INT,
            @Value2 INT,
            @tmpValue INT

    --DECLARE COUNTER
    DECLARE @Counter INT
    SET @Counter = 1

    --DECLARE CURSOR FOR QUERY
    DECLARE cTable1 CURSOR READ_ONLY FOR
        SELECT ID,Value1, Value2
        FROM Table1 

    OPEN cTable1

    --FETCH VARIABLES
    FETCH NEXT FROM cTable1 INTO @ID, @Value1, @Value2

    --LOOP 
    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF (@Value2 = '' OR @Value2 is NULL)
        BEGIN
            --UPDATE Table1.Value2 with next lowest Table1.Value2 > Table1.Value1
            SET @tmpValue = (SELECT MIN(Value1) FROM Table2  WHERE Value1 > @Value1 AND ID = @ID)

            UPDATE Table1 
            SET Value2 = @tmpValue     
            WHERE ID = @ID

            --DELETE AFFECTED ROW FROM Table2
            DELETE FROM Table2 
            WHERE Value1 = @tmpValue AND ID = @ID;
        END
        ELSE
        BEGIN
            --INSERT ROW IN Table1 WITH ID, Value1 FROM Table2 
            SET @ID = (SELECT MIN(ID) FROM Table2)
            SET @tmpValue = (SELECT MIN(Value1) FROM Table2 WHERE ID = @ID)

            INSERT INTO Table1(ID, Value1, Value2) 
            VALUES (@ID, @tmpValue, '')

            DELETE FROM Table2 
            WHERE ID = @ID
        END

        --FETCH NEXT VARIABLES
        FETCH NEXT FROM cTable1 INTO @ID, @Value1, @Value2
    END

    --CLOSE THE CURSOR TABLE
    CLOSE cTable1
    DEALLOCATE cTable1

大约有2万行,所以我希望存储过程可以完成所有操作。这是一次性的,所以我并不十分关注开销。

3 个答案:

答案 0 :(得分:0)

像这样的更新所需的基本查询非常清楚:

INSERT INTO Table1 (ID, Value1, Value2)
SELECT ID,
    Value1,
    [Empty]
From Table2 t2
LEFT JOIN Table1 t1
    ON t2.ID = t1.ID
    AND t2.Value1 = t1.Value1
LEFT JOIN Table1 t1a
    ON t2.ID = t1a.Id
    AND t2.Value1 = t1a.Value2
WHERE t1.Id IS NULL
    AND t1a.Id IS NULL

DELETE FROM Table2

然后我会像这样执行插入:

let result = days_in_month.map(
    year => year.map(
        (days) => new Array(days)
    )
);

请注意,这符合您的要求,但可能不符合您的实际要求 - @JeroenMostert的评论涵盖了其中一些问题。

答案 1 :(得分:0)

以下查询似乎产生了您想要的输出:

=if(countif(A1:A5,5)>=1,sum(A1:A5)+9,sum(A1:A5)-3)

考虑到这一点,一个简单的declare @Table1 table ( Id varchar(30) not null, Value1 int null, Value2 int null ); declare @Table2 table ( Id varchar(30) not null, Value int null ); insert into @Table1 (Id, Value1) values ('ID1', 123), ('ID4', 111); insert into @Table2 (Id, Value) values ('ID1', 224), ('ID1', 331), ('ID4', 210), ('ID4', 551); select t2.Id, case when t2.Value = min(t2.Value) over(partition by t1.Id) then t1.Value1 else t2.Value end as [V1], case when t2.Value = min(t2.Value) over(partition by t1.Id) then t2.Value end as [V2] from @Table1 t1 left join @Table2 t2 on t1.Id = t2.Id where t1.Value1 < t2.Value; 就可以解决问题:

MERGE

我可能会遇到一些边缘情况,但原则上这应该有用。

答案 2 :(得分:0)

试试这个

;With updateData as (
Select Id , Value1 , row_number() over ( partition by id order by value1 ) rowNumber from table2
)
Update table1 set value2 = t.value1 from updateData t where t.Id = table1.Id and t.rowNumber=1 

;With insertData as(
Select Id , Value1 , row_number() over ( partition by id order by value1 ) rowNumber from table2
)
Insert into table1(id,value1)
Select t.id , t.value1 from insertData t
Where  t.rowNumber>1