简体   繁体   English

在UPDATE语句中使用WHERE子句

[英]Using WHERE clauses in an UPDATE statement

I have an update statement that's like this: 我有一个像这样的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;

What I'm trying to do, is update the same table, but different users in that table, with the count of friend requests received for one user, and the count of friend requests sent by another user. 我想要做的是更新同一张表,但该表中的用户不同,其中一个用户收到的好友请求计数,以及另一用户发送的好友请求计数。

What I'm doing works if I remove the where clauses, but then, that updates all the users in the entire table. 如果删除where子句,那么我正在执行的操作将起作用,但是随后,它将更新整个表中的所有用户。

Any idea how I can do something like this with the where clauses in there or achieve the same results using another approach? 知道如何使用where子句执行类似的操作where或者使用另一种方法获得相同的结果吗?

( As proposed in several other answers, obviously, you could run two separate statements, but to answer the question you asked, whether it was possible, and how to do it... ) 显然,正如在其他几个答案中所建议的那样,您可以运行两个单独的语句,但是要回答您所问的问题,是否可能以及如何执行此操作...

Yes, it is possible to accomplish the update operation with a single statement. 是的,可以用一条语句完成更新操作。 You'd need conditional tests as part of the statement (like the conditions in the WHERE clauses of your example, but those conditions can't go into a WHERE clause of the UPDATE statement. 您需要将条件测试作为语句的一部分(例如示例中的WHERE子句中的条件,但是这些条件不能放入UPDATE语句的WHERE子句中。

The big restriction we have with doing this in one UPDATE statement is that the statement has to assign a value to both of the columns, for both rows. 我们在一个UPDATE语句中执行此操作的最大限制是该语句必须为两个行的两个分配一个值。

One "trick" we can make use of is assigning the current value of the column back to the column, eg 我们可以利用的一个“技巧”是将列的当前值分配回该列,例如

 UPDATE mytable SET mycol = mycol WHERE ...

Which results in no change to what's stored in the column. 这不会更改列中存储的内容。 ( That would still fire BEFORE/AFTER update trigger on the rows that satisfy the WHERE clause , but the value currently stored in the column will not be changed.) 这仍然会在满足WHERE子句的行上触发BEFORE / AFTER更新触发器 ,但是当前存储在该列中的不会更改。)

So, we can't conditionally specify which columns are to be updated on which rows, but we can include a condition in the expression that we're assigning to the column. 因此,我们无法有条件地指定要在哪些行上更新哪些列,但可以在要分配给该列的表达式中包含一个条件。 As an example, consider: 例如,请考虑:

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

For rows where foo=1 evaluates to TRUE, we'll assign 'bar' to the column. 对于foo = 1计算为TRUE的行,我们将“ bar”分配给该列。 For all other rows, the value of the column will remain unchanged. 对于所有其他行,该列的值将保持不变。

In your case, you want to assign a "new" value to a column if a particular condition is true, and otherwise leave it unchanged. 对于您的情况,如果特定条件为true,则想为列分配“新”值,否则保持不变。

Consider the result of this statement: 考虑以下语句的结果:

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);

(I've omitted the subqueries that return the count values you want to assign, and replaced that with the "expr1" and "expr2" placeholders. This just makes it easier to see the pattern, without cluttering it up with more syntax, that hides the pattern.) (我省略了返回要分配的计数值的子查询,并用“ expr1”和“ expr2”占位符替换了这些子查询。这只是使模式更易于查看,而不会因使用更多语法而使模式杂乱无章,隐藏图案。)

You can replace expr1 and expr2 in the statement above with your original subqueries that return the counts. 您可以用返回计数的原始子查询替换上面语句中的expr1expr2


As an alternative form, it's also possible to return those counts on a single row, using in an inline view (aliased as v here), and then specify a join operation. 作为一种替代形式,也可以使用内联视图(在此别名为v )在单行上返回这些计数,然后指定联接操作。 Something like this: 像这样:

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)

Since the inline view returns a single row, we don't need any ON clause or predicates in the WHERE clause. 由于内联视图返回一行,因此我们不需要WHERE子句中的任何ON子句或谓词。 (*I typically include the CROSS keyword here, but it could be omitted without affecting the statement. My primary rationale for including the CROSS keyword is to make the intent clear to a future reader, who might be confused by the omission of join predicates, expecting to find some in the ON or WHERE clause. The CROSS keyword alerts the reader that the omission of join predicates was intended.) (*我通常在此处包括CROSS关键字,但是可以在不影响语句的情况下将其省略。我加入CROSS关键字的主要理由是让将来的读者清楚其意图,因为将来的读者可能会因省略联接谓词而感到困惑,希望在ON或WHERE子句中找到某些内容。CROSS关键字会警告读者要省略连接谓词。)

Also note that the statement would work the same even if we omitted the predicates in the WHERE clause, we could spin through all the rows in the entire table, and only the rows with userId=1 or userId=2 would be affected. 还要注意,即使我们省略了WHERE子句中的谓词,该语句也将工作相同,我们可以遍历整个表中的所有行,并且仅影响userId = 1或userId = 2的行。 (But we want to include the WHERE clause, for improved performance; there's no reason for us to obtain locks on rows that we don't want to modify.) (但是,我们希望包括WHERE子句,以提高性能;没有理由让我们获得对不想修改的行的锁定。)

So, to summarize: yes, it is possible to perform the sort of conditional update of two (or more) rows within a single statement. 因此,总结一下:是的, 可能在单个语句中对两行(或更多行)执行条件更新。 As to whether you want to use this form, or use two separate statements, that's up for you to decide. 至于您要使用此表单还是使用两个单独的语句,则由您决定。

What you're trying to do is two updates try splitting these out: 您尝试做的是两次更新,尝试将它们分开:

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;

There may be a way using CASE statements to dynamically chose a column but I'm not sure if that's possible. 可能有一种使用CASE语句动态选择列的方法,但我不确定是否可行。

You are trying to update two different rows at the same time. 您正在尝试同时更新两个不同的行。 That is not possible. 这是不可能的。 Use two update queries then. 然后使用两个更新查询。

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

and

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

Tell me if that works or not. 告诉我是否可行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM