我有桌子和物品。每个项目都有id,item_type(比方说 - 书籍,音频,视频,电子书),插入时间和标志:
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
我想更新具有不同item_type的3个最旧行的列标志,对于上面的数据,这些行的ID为1,3,5。
但我不知道如何表达item_type对于更新的行必须不同的条件。谢谢你的建议。我感谢您的帮助。理查德
编辑:如果描述令人困惑,请道歉: 我想更新总是3行,每行不同 item_type。不是3本书,3个视频,......
广告排序 - 这是真的我可以按ID排序,而不是时间戳。这个演示是简化的,在实际应用中,我将使用修改时间戳进行排序。
答案 0 :(得分:1)
这是满足指定要求的一种方法。
(请注意,我们没有保证每个item_type的created
列的唯一性,并且要求查询更新AT MOST三行,每个item_type一行。此查询假定“id
”列是主键,或至少是唯一键。)
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
GROUP BY p.item_type
ORDER BY oldest
LIMIT 3
) q
ON q.item_type = r.item_type
AND q.oldest = r.created
GROUP BY r.item_type
) s
ON s.id = t.id
SET t.sign = 0
是的,这看起来有点讨厌。我们稍微打开它。
别名为“q
”的内嵌视图最多可获得三行,其中包含三个不同的item_type,以及每个item_type的最早“created
”值。这就是那里的一半战斗。
别名为“s
”的内联视图获得与“id
”中的行匹配的单行的“q
”值。 (我们需要这样做,因为我们没有得到保证,不会有两行或更多行匹配“item_type
”和“created
”,这样就有可能更新更多内容超过三行。)
-- test case
CREATE TABLE thetable (id INT, item_type VARCHAR(9), created TIMESTAMP, `sign` INT);
INSERT INTO thetable VALUES
('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);
SELECT * FROM thetable;
是否很难修改此UPDATE查询,以便更新最旧的行的符号并且其符号为空?
如果您的意思是您希望语句像它一样工作,但只对表中符号列中包含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
如果您的意思是其他内容,则修改会有所不同。
答案 1 :(得分:0)
此查询将为您提供每种项目类型的最早记录:
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
答案 2 :(得分:0)
您可以使用以下内容:
SELECT * FROM MyTable GROUP BY item_type ORDER BY created DESC LIMIT 3
使用group by
为您提供唯一的item_type
,以及order by created
的后代顺序以及limit 3
,将为您提供最早的三个
答案 3 :(得分: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;
以下是对数据的最终更改:
+----+-----------+---------------------+------+
| id | item_type | created | sign |
+----+-----------+---------------------+------+
| 1 | book | 2014-01-20 08:54:00 | 1 |
| 2 | book | 2014-01-15 15:40:24 | NULL |
| 3 | audio | 2014-01-20 08:54:00 | 1 |
| 4 | audio | 2014-01-17 15:40:24 | NULL |
| 5 | ebook | 2014-01-20 08:54:00 | 1 |
| 6 | video | 2014-01-19 15:40:24 | NULL |
+----+-----------+---------------------+------+
在进一步思考并查看其他人的解决方案之后,如果我们不限制在单个SQL语句中执行此操作,我认为这会容易得多。
选择具有不同item_types的三个最早的条目,首先是创建的时间戳,然后只是在有条件的情况下,匹配该时间戳的条目,选择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只选择一个。
+-----------+------+
| 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
以为我还测试了其他用户提供的其他一些解决方案,但它们似乎也有效。因此,当UPDATE允许子查询时,必须有一个非常微妙的规则。
我建议更简单的解决方案,因为它更容易理解,编码,调试和维护。所以在两个声明中这样做并称之为胜利。