我是 MySQL 新手。我正在制作一张包含运动员(姓名作为主键)及其跑步时间的表格。
在上一次训练中,Tom 记录为 32 m 46 s,Joe 记录为 34 m 33 s。
我需要一个语句(我使用Python)来更新表格,以便在第一个可用单元格中添加新时间,表格示意图如下:
Name G1 G2 G3
---------------------------------
Tom 33m21s 31m54s null
Joe 35m03s null null
因此,对于 Tom,时间应位于 G3 列,而对于 Joe,时间应位于 G2 列。
表格应如下所示:
Name G1 G2 G3
----------------------------------
Tom 33m21s 31m54s 32m46s
Joe 35m03s 34m33s null
我正在尝试使此任务尽可能自动化,因此我不想每次都指定新时间应该在哪一列中。
我已经尝试过这段代码,但每次都必须指定列: 我不知道“SET”后要插入什么
sqlMP = "UPDATE time SET ... WHERE player = %s AND G1 IS NULL"
感谢您的帮助
您可以按如下方式使用
coalesce()
:
update time_table set
g1 = coalesce(%s, g1),
g2 = case when g1 is not null and g2 is null then %s else g2 end,
g3 = case when g1 is not null and g2 is not null and g3 is null then %s else g3 end
where player = %s
请注意,这需要您传递目标值三次。
但是,我建议您这不是存储数据的正确方式。玩家和时间之间是一对多的关系;您应该将每个时间/玩家元组存储在不同的行上。这将大大简化逻辑(新时间只是表中的插入),并避免您将来遇到更多问题(例如:如果您想为每个玩家存储 4 次而不是 3 次怎么办?)。
Gordon L’inoffensif 在他的回答中解释说,在 MySQL 中,在
SET
中执行的更改可以从以下内容中看到 - 因此上述查询将无法按预期工作。
我认为我们可以通过恢复分配顺序来解决这个问题:
update time_table set
g3 = case when g1 is not null and g2 is not null and g3 is null then %s else g3 end,
g2 = case when g1 is not null and g2 is null then %s else g2 end,
g1 = coalesce(%s, g1)
where player = %s
MySQL 与其他数据库和标准不同,因为当您更新列时,新值会在 set
的
right侧可见。请参阅代码后的参考。啊啊啊!
这使得这相当具有挑战性。假设每个名称一行,您可以使用自连接:
update time_table tt join
time_table ttold
on tt.name = ttold.name cross join
(select %s as new_value -- just a convenience
) v
set tt.g1 = (case when ttold.g1 is null
then v.new_value
else ttold.g1
end),
tt.g2 = (case when ttold.g1 is null and ttold.g2 is null
then v.new_value
else ttold.g2
end)
tt.g3 = (case when ttold.g1 is null and ttold.g2 is null and ttold.g3 is null
then v.new_value
else ttold.g3
end);
正如 GMB 指出的,这是一个非常糟糕的数据结构。您应该将值存储在单独的行中,而不是单独的值中。
有关此内容的文档位于此处:
以下语句中的第二个赋值将 col2 设置为当前(更新的)col1 值,而不是原始 col1 值。结果是 col1 和 col2 具有相同的值。 此行为与标准 SQL 不同。
UPDATE t1 SET col1 = col1 + 1, col2 = col1;