在UPDATE语句中使用WHERE子句

时间:2014-10-02 12:07:05

标签: mysql sql

我有update语句,如下所示:

update user_stats set
    requestsRecd = (select count(*) from requests where requestedUserId = 1) where userId = 1,
    requestsSent = (select count(*) from requests where requesterUserId = 2) where userId = 2;

我正在尝试做的是更新同一个表,但该表中的不同用户,一个用户收到的好友请求数,以及另一个用户发送的好友请求数。

如果我删除了where子句,那么我正在做的是什么,然后,它会更新整个表中的所有用户。

我知道如何使用where条款执行此类操作,或使用其他方法获得相同的结果?

3 个答案:

答案 0 :(得分:2)

正如在其他几个答案中提出的那样,显然,您可以运行两个单独的陈述,但要回答您提出的问题,是否可能,以及如何做到这一点...... )< / p>

是的,可以使用单个语句完成更新操作。您需要将条件测试作为语句的一部分(例如示例的WHERE子句中的条件,但这些条件不能进入UPDATE语句的WHERE子句。

我们在一个UPDATE语句中执行此操作的一个重要限制是,该语句必须为列的两个分配一个值,对于两个行。

我们可以利用的一个“技巧”是将列的当前值分配回列,例如

 UPDATE mytable SET mycol = mycol WHERE ...

这导致列中存储的内容无变化。 (那仍然会在满足WHERE子句的行的BEFORE / AFTER更新触发器上触发,但当前存储在列中的改变。)

因此,我们无法有条件地指定要在哪些行上更新哪些列,但我们可以在我们分配给的表达式中包含一个条件专栏。例如,请考虑:

 UPDATE mytable SET mycol = IF(foo=1, 'bar', mycol)

对于foo = 1的行计算为TRUE,我们将“bar”分配给列。对于所有其他行,列的值将保持不变。

在您的情况下,如果特定条件为真,您希望为列分配“新”值,否则保持不变。

考虑这个陈述的结果:

UPDATE user_stats t
  SET t.requestsRecd = IF(t.userId=1, expr1, t.reqestsRecd) 
    , t.requestsSent = IF(t.userId=2, expr2, t.reqestsSent) 
WHERE t.userId IN (1,2);

(我省略了返回您要分配的计数值的子查询,并将其替换为“expr1”和“expr2”占位符。这样可以更容易地查看模式,而不会使其更加混乱语法,隐藏模式。)

您可以使用返回计数的原始子查询替换上述语句中的expr1expr2


作为替代形式,还可以在单​​行上返回这些计数,使用内联视图(此处别名为v),然后指定连接操作。像这样:

UPDATE user_stats t
 CROSS
  JOIN ( SELECT (select count(*) from requests where requestedUserId = 1) AS c1
              , (select count(*) from requests where requesterUserId = 2) AS c2
       ) v
   SET t.requestsRecd = IF(t.userId=1, v.c1 ,t.reqestsRecd) 
     , t.requestsSent = IF(t.userId=2, v.c2 ,t.reqestsSent)
 WHERE t.userId IN (1,2)

由于内联视图返回单行,因此WHERE子句中不需要任何ON子句或谓词。 (*我通常在这里包含CROSS关键字,但它可以在不影响语句的情况下被省略。我包含CROSS关键字的主要理由是让未来的读者明白这个意图,他可能会因为省略连接谓词而感到困惑,期望在ON或WHERE子句中找到一些.CROSS关键字提醒读者有意省略连接谓词。)

另请注意,即使我们在WHERE子句中省略了谓词,语句也会一样,我们可以遍历整个表中的所有行,只有userId = 1或userId = 2的行会受到影响。 (但我们想要包含WHERE子句,以提高性能;我们没有理由获取我们不想修改的行的锁。)

因此,总结一下:是的, 可以在单个语句中执行两个(或更多)行的条件更新。至于您是否要使用此表单,或使用两个单独的语句,由您决定。

答案 1 :(得分:1)

你要做的是两个更新尝试拆分这些:

update user_stats set
    requestsRecd = (select count(*) from requests where requestedUserId = 1) where userId = 1;
update user_stats set
    requestsSent = (select count(*) from requests where requesterUserId = 2) where userId = 2;

可能有一种使用CASE语句动态选择列的方法,但我不确定这是否可行。

答案 2 :(得分:0)

您正尝试同时更新两个不同的行。这是不可能的。然后使用两个更新查询。

update user_stats set
requestsRecd = (select count(*) from requests where requestedUserId = 1) where userId = 1;

update user_stats set
requestsSent = (select count(*) from requests where requesterUserId = 2) where userId = 2;

告诉我这是否有效。