Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MySQL-更新一列中具有不同(非唯一)值的行_Mysql_Sql Update_Greatest N Per Group - Fatal编程技术网

MySQL-更新一列中具有不同(非唯一)值的行

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、项目类型(比如-书籍、音频、视频、电子书)、插入时间和签名:

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