使用相同的SQL Server case语句更新多个列

时间:2015-02-06 20:30:53

标签: sql sql-server tsql case-when

我有以下UPDATE语句

UPDATE PAYMENT_HISTORY
SET request_status_id =
CASE
  WHEN PHP.request_status_id = PHP.prevRequest_status_id THEN NULL 
  ELSE PHP.request_status_id
END,
  is_changed =
CASE
  WHEN PHP.request_status_id = PHP.prevRequest_status_id THEN 0
  ELSE 1
END    

是否可以使用单个case语句更新两列?

5 个答案:

答案 0 :(得分:2)

  

是否可以使用单个case语句更新两列?

没有。 CASE表达式具有单个原子值。单个CASE表达式不能包含两个字段的值。您只能使用request_status_id来同时设置is_changedCASE ... END

可以在同一UPDATE语句中更新这两个字段,但不能更新CASE表达式。

但是,您的表达式有问题,而且此处的分配不会相互衔接。语句开始执行时,锁定的数据将被锁定。它使用在语句运行之前存在的表。

考虑:

CREATE TABLE TestTable (
    Odd TINYINT NOT NULL,
    Even TINYINT NOT NULL,
    PRIMARY KEY (Odd, Even)
);

INSERT INTO TestTable (Odd, Even) VALUES (1, 2);
INSERT INTO TestTable (Odd, Even) VALUES (3, 4);
INSERT INTO TestTable (Odd, Even) VALUES (5, 6);
INSERT INTO TestTable (Odd, Even) VALUES (7, 8);

SELECT * FROM TestTable;

UPDATE TestTable SET Odd = Even, Even = Odd;

SELECT * FROM TestTable;

SQLFiddle

除非你做的事情像递归CTE一样奇怪,否则数据几乎都是在语句执行之前设置的。

答案 1 :(得分:1)

基本上不可能。您可以将CASE..END移动到功能并以这种方式调用它,但影响是可记录的......

UPDATE PAYMENT_HISTORY
SET 
    request_status_id = dbo.fnCalc(PHP.request_status_id, PHP.prevRequest_status_id, 1),
    is_changed = dbo.fnCalc(PHP.request_status_id, PHP.prevRequest_status_id, 2)

答案 2 :(得分:1)

请参阅BOL for update子句:https://msdn.microsoft.com/en-us/library/ms177523.aspx

具体为column_name = { expression | DEFAULT | NULL }

只允许在右侧表达式,因此您无法编写表达式来选择要更新的列。

答案 3 :(得分:1)

或者如果逻辑如此简单,您可以使用2次更新来完成,第二次更新基于第一次更新的结果。但同样,你需要有理由这样做。

UPDATE PAYMENT_HISTORY
  SET request_status_id =
   CASE
     WHEN PHP.request_status_id = PHP.prevRequest_status_id THEN NULL 
     ELSE PHP.request_status_id
   END

UPDATE PAYMENT_HISTORY SET 
  is_changed = 
    CASE
      WHEN request_status_id is NULL THEN 0
      ELSE 1
    END    

OR执行效率更高(第二次更新只会更新需要更新的行)

UPDATE PAYMENT_HISTORY
  SET 
   request_status_id =
     CASE
       WHEN PHP.request_status_id = PHP.prevRequest_status_id THEN NULL 
       ELSE PHP.request_status_id
     END,
   is_changed=0


UPDATE PAYMENT_HISTORY SET 
    is_changed = 1
  WHERE 
    request_status_id is not NULL 

答案 4 :(得分:0)

是的,可以使用变量。

UPDATE PAYMENT_HISTORY
SET request_status_id =
CASE
  WHEN PHP.request_status_id = PHP.prevRequest_status_id 
    THEN coalesce((@ischanged:=0)+null,NULL) 
    ELSE coalesce((@ischanged:=1)+null,PHP.request_status_id)
  END,
  is_changed = @ischanged

一般来说:

UPDATE mytable
SET
  a = CASE 
    WHEN [condition1]
      THEN coalesce((@b:= [b expression]) +null, (@c:= [c expression]) +null, [a expression])
    WHEN [condition2]
      THEN coalesce((@b:= [b expression]) +null, (@c:= [c expression]) +null, [a expression])
    ELSE coalesce((@b:= [b expression]) +null, (@c:= [c expression]) +null, [a expression])
    END,
  b = @b,
  c = @c

附加到coalesce'+ null'的每个输入参数,以确保执行表达式并将结果存储在变量中,但是coalesce函数不返回表达式的结果。

在MySQL上测试。