2017-08-17 16 views
0

20K行程度を一度に移行してください。 SQLから10年以上離れていて、苦労しています。SQL Serverのストアドプロシージャ:最小値のUPDATE、値が既にある場合はINSERT

私はこれについて完全に間違っているかもしれません。既にValue2がある場合を除き、Table2.Value1の最低値でTable1.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万行があるので、ストアドプロシージャがすべてを達成することを望んでいます。それは一回限りだから、オーバーヘッドについて懸念しているスーパーではない。

+2

それでは 'ID1、111'と' Table2'内の別の行がありますか? 「ID1,444」はどうですか?これらのケースで最終的な結果はどうなるでしょうか? 1つのテーブルに結果を構築するには、 'MIN(Value)GROUP BY ID'、' UNION'、 'ROW_NUMBER()'、 'CROSS APPLY'が便利です。トランザクションで 'INSERT INTO'、' MERGE'または別々の 'INSERT' /' UPDATE'文のどちらかを使って、 'Table1'をその結果のようにすることができます(そして、' Table2'は単純にその行をすべて削除することができます)。 10年後にSQLを使用していないのであれば、カーソルが存在することをまだ思い出しているのは残念です。:-P –

+0

目的を達成するためにストアドプロシージャは必須ですか?これは、CASE文とINSERT INTO – Isaiah3015

+0

@ JeroenMostertで一時テーブルにテーブルをつかんで簡単に行うことができます。私はMERGEを検討する必要がありますが、私はそれを達成する別の方法として考えていました。 – Zebrahead

答えて

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 

注:

UPDATE Table1 
SET VALUE2 = (
    SELECT MIN(t2.Value1) 
    FROM Table2 t2 
    WHERE t2.Value1 > Table1.Value1 
     AND t2.ID = Table1.ID 
    ) 

私は、このように挿入を行いますあなたの実際の要件を満たしていない - @ JeroenMostertのコメントは、それらの問題の数をカバーしています。

+0

私の更新セクションが正常に動作します。混乱させて申し訳ありません。私は言葉を修正しました。私はあなたが間違っていない限り、T1.Value2に値があるかどうかをチェックしないので、あなたが提案したUPDATEステートメントは動作しないと思います。簡単にそのチェックを挿入するのは簡単ですが、私の現在のUPDATEステートメントよりも優れた解決策ですか? 私は実際に練習をしていませんので、あなたが提案するLEFT JOINをリフレッシュする必要があります。 – Zebrahead

0

次の問合せは、ご希望の出力を生成するようだ:念頭に置いて

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は、トリックを行います:

merge @Table1 t 
using (
    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 
) s on s.Id = t.Id and s.V1 = t.Value1 
when not matched by target then 
    insert (Id, Value1, Value2) 
    values (s.Id, s.V1, s.V2) 
when matched then 
    update set Value2 = s.V2; 

私はいくつかのエッジケースと間違っているかもしれません、原則としてこれはうまくいくはずです。

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 
関連する問題