SQL:如果 *condition* 在另一行上,则更新一行
Posted
技术标签:
【中文标题】SQL:如果 *condition* 在另一行上,则更新一行【英文标题】:SQL: update a row if *condition* on another row 【发布时间】:2020-08-03 04:44:14 【问题描述】:我的 SQL 有问题。
当且仅当另一行上的值与条件匹配时,我想更新给定行上的值;然后更新第二行的另一个值。
好吧,这样解释不清楚,所以代码如下(我要使用mysqli绑定参数):
--mariaDB:
UPDATE `accountlist` JOIN `data` ON `accountlist`.`id`=`data`.`id`
SET `upvotes`= `upvotes` + (`user`= ?),
`allow` = (CASE WHEN `accountlist`.`id` = ?
THEN ?
ELSE `allow`
END)
WHERE (SELECT `allow` FROM `data` WHERE `id` = ?) < ?;
--mysql:
UPDATE `accountlist` JOIN `data` ON `accountlist`.`id`=`data`.`id`
SET `upvotes`= `upvotes` + (`user`= ?),
`allow` = (CASE WHEN `accountlist`.`id` = ?
THEN ?
ELSE `allow`
END)
WHERE `data`.`id` = ? AND `allow` < ?;
--params sample: "admin", 2, "2020-04-20", 2, "2020-04-20"
-- (same value here means always same value)
我必须同时保留 MySQL 和非 MySQL 版本,因为我在 localhost 和我的主机上有不同的数据库,并且由于某种原因第一个版本不适用于 MySQL。
data
是另一个与accountlist
一对一关系的表(它们始终具有相同的行数和相同的id
s)
无论如何,我将调用 user=?
所在的行 row 1 和 accountlist.id=?
所在的行 row 2 以简化所有内容。
我想做的是:
-
如果第2行上的
allow
小于?
,则更新第1行上的user
更新第2行上的allow
(如果第2行上的allow
小于?
)
第二点的条件并不重要,因为它会自我更新,但这是我能够做到这一点的唯一方法。
我的问题:
第一段代码(非 MySQL)更新 第 1 行上的upvotes
,但永远不会更改 第 2 行上的 allow
。
第二段代码 (MySQL) 更新 第 2 行 上的 arrow
,但永远不会更改 第 1 行 上的 user
。
您是否有任何解决方案,可能意味着唯一的 MySQL + 非 MySQL 版本?
更新:
这里是一个例子:
accountlist data
|------------|---------------| |------------|--------------|----------|
| id | user | | id | allow | upvotes |
|------------|---------------| |------------|--------------|----------|
A: | 1 | admin | | 1 | 2020-04-18 | 2 |
B: | 2 | foo | | 2 | 2020-04-20 | 0 |
C: | 3 | bar | | 3 | 2020-04-22 | 1 |
|------------|---------------| |------------|--------------|----------|
参数:“管理员”、2、“2020-04-20”、2、“2020-04-20”
B 行上的allow
不低于2020-04-20
:
参数:“管理员”、2、“2020-04-22”、2、“2020-04-22”
B 行 上的allow
低于2020-04-20
:
upvotes
增加了 (2
->3
)
B 行 上的allow
已更新 (2020-04-20
->2020-04-22
)
参数:“bar”、1、“2020-04-19”、1、“2020-04-19”
A 行 上的allow
低于2020-04-19
:
upvotes
增加了 (1
->2
)
A 行 上的allow
已更新 (2020-04-18
->2020-04-19
)
更新 2:
我想做什么:
如果 user 1 想要给 user 2 投票(每个人每天最多可以给其他人投票一次),当它点击一个按钮时,allowed
(在他的行)是与后天相比:
allowed
等于后天,则表示用户1已经为某人投票(他可能是用户2 ,用户 3 或其他人),所以没有任何变化
如果allowed
低于次日,这意味着用户1 可以投票给某人,所以upvote
在用户2 的行增加,用户 1 的行上的allow
更新为后一天
不用担心“如果 user 1 或 user 2 实际不存在怎么办?”或“如果 user 1 怎么办? > 试图给自己投票?* 因为我在我的 php 代码中检查了它。
【问题讨论】:
这可能是可行的,但你的问题目前还不清楚。请以表格文本的形式提供示例数据和预期结果,以阐明您的实际需求(通常,5 到 10 行就足够了)。 如何定义“第 1 行”?基于id
?基于某种顺序的“下一个”,如果是,是什么顺序?
为什么不能对两个数据库都使用第二个版本?
@GMB 我更新的问题够了吗?
你为什么不做类似“检查用户是否被允许投票、增加投票、更新日期”之类的事情?无论如何,您的 mariadb 代码应该可以工作。对于所有边缘情况(例如,它不检查第 1 行是否存在),它不快速或不美观,但它不应该有您描述的问题 - 除非data
中的第 1 行或第 2 行没有匹配条目。请检查并澄清data
是否相关,您永远不会提及它。让这个 mariadb 查询在 mysql 中工作是微不足道的(“我这样做是因为我在 MySQL 中遇到错误”比“我读到它”更好地解释了你的原因),但你应该先澄清你的要求。
【参考方案1】:
让我们来看看。首先,对每一列进行限定,以帮助查看哪一列在哪个表中:
UPDATE a JOIN d ON a.`id` = d.`id`
SET d.`upvotes`= d.`upvotes` + (a.`user`= ?),
d.`allow` = (CASE WHEN a.`id` = ?
THEN ?
ELSE d.`allow`
END)
WHERE d.`id` = ? AND d.`allow` < ?;
哦,这两张桌子在id
上是 1:1 的。所以让我们假设它们是同一张桌子。 (你可能应该这样做。1:1 通常不是一个好的架构设计。)
UPDATE ad
SET `upvotes`= `upvotes` + (`user`= ?),
`allow` = (CASE WHEN `id` = ?
THEN ?
ELSE `allow`
END)
WHERE `id` = ? AND `allow` < ?;
现在很明显CASE
被浪费了。所以查询简化为
UPDATE ad
SET `upvotes`= `upvotes` + (`user`= ?),
`allow` = ?
WHERE `id` = ? AND `allow` < ?;
现在让我们回到有 2 个表:
UPDATE a JOIN d ON a.`id` = d.`id`
SET d.upvotes = d.upvotes + (a.user = ?),
d.allow = ?
WHERE d.id = ? AND d.allow < ?;
这导致了另一种形式。 (不知道这样好不好)
UPDATE d
SET d.upvotes = d.upvotes +
( ( SELECT user = ? FROM a WHERE a.id = d.id ) )
d.allow = ?
WHERE d.id = ? AND d.allow < ?;
或者,(同样可能没有任何显着差异):
UPDATE d
SET d.upvotes = d.upvotes +
EXISTS ( SELECT user = ? FROM a WHERE a.id = d.id )
d.allow = ?
WHERE d.id = ? AND d.allow < ?;
【讨论】:
它不起作用:它正确更新允许我称之为 row 2 (其中id=?
)但用户在每种情况下都保持不变(您的所有版本)。有关更多信息,请参阅我和 @Solarflare 之间的 cmets:我们找到了 some ideas,但它们都有一些问题,从 MariaDB 和 MySQL 之间的兼容性到与您的类似的版本在某些情况下不起作用。我还想出了一些可行的方法(请参阅链接),但这似乎是一种解决方法而不是解决方案
@Foxel - 第一个“更新”没有显示user
需要更改;请相应地编辑它。【参考方案2】:
我已尝试为您的问题找到解决方案,并且可能有答案 我在这里正确理解了工作流程: 每个用户每天可以投票 1 次
-
user1 点赞 user2
user1 今天已经投票了吗?
->是的:什么都不做
-> 否:将 user1 的日期和 +1 更改为 user2 的投票
在该示例中:“admin”、2、“2020-04-20”、2、“2020-04-20”
2 => 用户1 admin => user2 "2020-04-20" => 投票日期我说的对吗? 如果是的话,我的解决方案
mariadb
UPDATE data SET upvotes = CASE WHEN id = (SELECT id FROM accountlist WHERE accountlist.user = ?)
AND
(SELECT allow FROM data inner join accountlist on accountlist.id = data.id
where accountlist.id = ? )< ?
THEN upvotes + 1
ELSE upvotes
END,
allow = CASE WHEN id = ?
THEN ?
ELSE allow
END
mysql
UPDATE data
SET upvotes = CASE WHEN id = (SELECT id FROM (select * from accountlist) as al WHERE al.user = "bar")
AND
(SELECT allow FROM (select * from data) as d inner join (select * from accountlist) as al1 on al1.id = d.id where al1.id = 1)<"2020-04-19"
THEN upvotes + 1
ELSE upvotes
END,
allow = CASE WHEN id = 1
THEN "2020-04-19"
ELSE allow
END;
创建数据库:
accountlist data
|------------|---------------| |------------|--------------|----------|
| id | user | | id | allow | upvotes |
|------------|---------------| |------------|--------------|----------|
A: | 1 | admin | | 1 | 2020-04-18 | 2 |
B: | 2 | foo | | 2 | 2020-04-20 | 0 |
C: | 3 | bar | | 3 | 2020-04-22 | 1 |
|------------|---------------| |------------|--------------|----------|
具有价值: "admin", "2", "2020-04-20", "2", "2020-04-20" => 没有修改
“管理员”、“2”、“2020-04-22”、“2”、“2020-04-22”
accountlist data
|------------|---------------| |------------|--------------|----------|
| id | user | | id | allow | upvotes |
|------------|---------------| |------------|--------------|----------|
A: | 1 | admin | | 1 | 2020-04-18 | 3 |
B: | 2 | foo | | 2 | 2020-04-22 | 0 |
C: | 3 | bar | | 3 | 2020-04-22 | 1 |
|------------|---------------| |------------|--------------|----------|
"酒吧", 1, "2020-04-19", 1, "2020-04-19" =>
accountlist data
|------------|---------------| |------------|--------------|----------|
| id | user | | id | allow | upvotes |
|------------|---------------| |------------|--------------|----------|
A: | 1 | admin | | 1 | 2020-04-19 | 3 |
B: | 2 | foo | | 2 | 2020-04-22 | 0 |
C: | 3 | bar | | 3 | 2020-04-22 | 2 |
|------------|---------------| |------------|--------------|----------|
通常可以正确运行(在线测试),但使用 2 语句而不是 1 语句会更简单。
【讨论】:
它适用于 MariaDB,但不适用于 MySQL。奇怪的事实是我在 fiddle 上尝试过它,它似乎甚至可以与 MySQL 一起使用(它有点修改但与 your one 的结果相同。有什么建议吗? 我安装 wamp 服务器并测试它 在您的小提琴上,当您将 sql 版本从 8.0 更改为 5.7 时,请求失败。您的服务器使用哪个版本? 带有 phpMyAdmin 的 MySQL 5.6 我已经尝试过link,即使在 5.7 中也一切正常。 phpmyadmin 没有错误?以上是关于SQL:如果 *condition* 在另一行上,则更新一行的主要内容,如果未能解决你的问题,请参考以下文章
SQL WHERE (conditions) AND (condition1 OR condition2) 不起作用
Mysql 为每一行检查是不是一个字段在另一个表中,如果不删除该行
SQL Server中的SUM,在JOIN的一侧有多行,另一侧在另一侧作为比较
BASH:试图在不引入空格的情况下在另一行上继续一个字符串[重复]