MySQL-更新一列中具有不同(非唯一)值的行
我有一张摆放物品的桌子。每个项目都有id、项目类型(比如-书籍、音频、视频、电子书)、插入时间和签名:MySQL-更新一列中具有不同(非唯一)值的行,mysql,sql-update,greatest-n-per-group,Mysql,Sql Update,Greatest N Per Group,我有一张摆放物品的桌子。每个项目都有id、项目类型(比如-书籍、音频、视频、电子书)、插入时间和签名: id| item_type | created (timestamp) | sign 1 | book | 2014-01-14 15:40:24 | NULL 2 | book | 2014-01-15 15:40:24 | NULL 3 | audio | 2014-01-16 15:40:24 | NULL 4 | audio | 2014-
id| item_type | created (timestamp) | sign
1 | book | 2014-01-14 15:40:24 | NULL
2 | book | 2014-01-15 15:40:24 | NULL
3 | audio | 2014-01-16 15:40:24 | NULL
4 | audio | 2014-01-17 15:40:24 | NULL
5 | ebook | 2014-01-18 15:40:24 | NULL
6 | video | 2014-01-19 15:40:24 | NULL
我想为3个不同项目类型的最旧行更新列标志,对于上面的数据,这些行的ID为1,3,5
但我不知道如何表示更新行的项类型必须不同的条件。谢谢你的建议。我感谢你的帮助。理查德
编辑:如果描述令人困惑,请道歉:
我想更新始终为3行,每行具有不同的项目类型。不是3本书,3段视频
广告排序-我确实可以按ID排序,而不是按时间戳排序。此演示是简化的,在实际应用中,我将使用修改时间戳排序。此查询将为每个项目类型获取最早的记录:
select item_type, min(created) as MinCreated
from MyTable
group by item_type
然后,您可以执行以下操作:
update MyTable a
inner join (
select item_type, min(created) as MinCreated
from MyTable
group by item_type
) b on a.item_type = b.item_type
and a.created = b.MinCreated
set sign = 1
SELECT * FROM MyTable GROUP BY item_type ORDER BY created DESC LIMIT 3
您可以使用以下内容:
update MyTable a
inner join (
select item_type, min(created) as MinCreated
from MyTable
group by item_type
) b on a.item_type = b.item_type
and a.created = b.MinCreated
set sign = 1
SELECT * FROM MyTable GROUP BY item_type ORDER BY created DESC LIMIT 3
使用
分组依据
可以为您提供唯一的项目类型
,按子代顺序创建的顺序
以及限制3
,将为您提供最早的三个以下是满足指定要求的一种方法
(请注意,我们没有保证每个项类型创建的列的唯一性,并且要求查询最多更新三行,每个项类型更新一行。此查询假设“id
”列是主键,或者至少是唯一键。)
是的,看起来有点恶心。让我们把它打开一点
别名为“q
”的内联视图最多可获取三行,其中包含三种不同的项类型,以及每个项类型最早的“创建的”
”值。这是战斗的一半
别名为“s
”的内联视图为与“q
”中的行匹配的单行获取“id
”值。(我们需要这样做,因为我们没有得到保证不会有两行或更多行具有匹配的“item\u type
”和“created
”,这就有可能更新三行以上。)
后续行动
修改此更新查询以更新最旧且符号为空的行的符号是否困难
如果您的意思是希望语句像它一样工作,但只对表中符号列中有NULL的行进行操作,就好像它假装符号列中不存在非NULL值的行一样,那么这是一个非常简单的更改
我们可以向内联视图中添加WHERE子句,如下所示:
UPDATE thetable t
JOIN ( SELECT r.item_type
, MIN(r.id) AS id
FROM thetable r
JOIN ( SELECT p.item_type
, MIN(p.created) AS oldest
FROM thetable p
WHERE p.sign IS NULL -- only consider rows with NULLs
GROUP BY p.item_type
ORDER BY oldest
LIMIT 3
) q
ON q.item_type = r.item_type
AND q.oldest = r.created
WHERE r.sign IS NULL -- only consider rows with NULLs
GROUP BY r.item_type
) s
ON s.id = t.id
SET t.sign = 0
如果您是指其他内容,则修改会有所不同。我测试了此解决方案:
SET @t := NULL;
SET @c := 0;
UPDATE n
SET sign = IF(@t = item_type, sign, IF(@c < 3, SIGN(@c:=@c+1), sign)),
item_type = IF(@t:=item_type, item_type, item_type)
ORDER BY item_type, created;
在进一步考虑这一点并查看其他人的解决方案之后,我认为如果我们不局限于在一条SQL语句中完成这项工作,那么这将容易得多
选择三个具有不同项类型的最早项,首先根据创建的时间戳,然后在与该时间戳匹配的项中选择id最低的项
SELECT item_type, MIN(id) AS id
FROM n
JOIN (
SELECT item_type, MIN(created) AS created
FROM n
GROUP BY item_type
ORDER BY created ASC LIMIT 3
) AS t USING (item_type, created)
GROUP BY item_type;
这将为您提供三个最早条目的id,每个条目类型只选择一个条目
+-----------+------+
| item_type | id |
+-----------+------+
| audio | 3 |
| book | 1 |
| ebook | 5 |
+-----------+------+
然后,您必须获取id并形成一个新的查询:
UPDATE n SET sign = 1 WHERE id IN (3,1,5);
我试图将这两个语句合并为一个UPDATE语句,但出现以下错误:
ERROR 1093 (HY000): You can't specify target table 'n' for update in FROM clause
我还测试了其他用户提供的一些其他解决方案,它们似乎很有效。所以当更新允许子查询时,必须有一个非常微妙的规则
我建议更简单的解决方案更好,因为它更容易理解、编码、调试和维护。因此,在两个语句中执行此操作并将其称为胜利。如果四个项目具有相同的创建时间
怎么办?@BillKarwin它们都将得到更新,因为它们都是最古老的。根据OP中的示例数据,此SQL语句将更新4行,包括行id=6。但是OP要求只更新3行。如果id
字段是自动递增的主键值,那么您可以安全地依赖它而不是日期-时间字段。@Ravinder,您假设行是按时间顺序插入的。我相信datetime
或timestamp
字段中的值不是手动插入的。这是因为,据我所知,没有人想手动输入秒的部分内容。@Ravinder-我在帖子中添加了解释。我可以在这个例子中使用ID。我使用了来自实际应用程序的逻辑,其中的行并不像Bill Karwin写的那样按时间顺序排列。+1@理查兹:我不知道你的问题为什么会被否决;我觉得你的问题很清楚很准确。我认为我提供的答案符合规定的要求;如果它不适合你,或者你有问题,请随时告诉我。它需要按升序创建以获得“最旧的”,降序将打赌“最新的”。我考虑过使用这种方法;但我认为如果项目类型不连续,就会出现问题。。。这里是否有可能更新给定项目类型的多行?(不是在示例数据中,而是在一个角落案例中,其中“最早”的行被排序:book、audio、book、audio、book、@spencer7593,很好的捕获。我添加了一个按项排序的类型来解决这个问题。我也想到了这个解决方案,在order by中添加了一个item\u type
,但问题是它不能确保我们得到三个“最早的”创建了item_type。如果我们使用所有item_type,并为每个item_type标记“最旧的”(很抱歉,我并不想批评您的工作)。您介绍的技术,在SQL中使用MySQL用户变量,功能非常强大,并且可以提供更好的性能(在某些情况下)与其他备选方案相比。@spencer7593,我看你是对的,这只适用于特定的样本数据,但它不一定选择具有ol的三个项目类型
ERROR 1093 (HY000): You can't specify target table 'n' for update in FROM clause