关于mysql:如果count(*)> n,则更新行

update row if count(*) > n

我的DB有这样的结构:

1
ID | text | time | valid

这是我目前的代码。 我正试图找到一种方法来做一个查询。

1
2
3
4
5
6
7
8
rows = select * from table where ID=x order by time desc;
n=0;
foreach rows{
    if(n > 3){
       update table set valid = -1 where rows[n];
    }
    n++
}

我正在检查给定ID存在多少行。 然后我需要为n> 3的所有行设置valid = -1;

有没有办法用一个查询来做到这一点?


您可以在WHERE子句中使用子查询,如下所示:

1
2
3
4
5
6
7
8
UPDATE table
   SET valid=-1
 WHERE (
         SELECT COUNT(*)
           FROM table tt
          WHERE tt.time > table.time
            AND   tt.ID = table.ID
) > 3

子查询计算具有相同ID和更晚时间的行。 对于最近的三行,此计数将为三或更少; 其余的将有更多的计数,因此他们的valid字段将被更新。


假设(id,time)具有UNIQUE约束,即没有两行具有相同的id且相同的time

1
2
3
4
5
6
7
8
9
10
11
12
13
UPDATE
    tableX AS tu
  JOIN
    ( SELECT time
      FROM tableX
      WHERE id = @X                      -- the given ID
      ORDER BY time DESC
      LIMIT 1 OFFSET 2
    ) AS t3
    ON  tu.id = @X                       -- given ID again
    AND tu.time < t3.time
SET
    tu.valid = -1 ;


1
2
3
4
5
6
7
update table
   set valid = -1
 where id in (select id
                from table
               where id = GIVEN_ID
            group by id
              having count(1) >3)

更新:我真的很喜欢dasblinkenlight的解决方案,因为它很整洁,但我想尝试以我的方式做到这一点,一个相当冗长的解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  update Table1
     set valid = -1
   where (id, time) in (select id,
                               time
                          from (select id,time
                                  from table1
                                 where id in (select id
                                                from table1
                                            group by id
                                              having count(1) >3)
                                -- and id = GIVEN_ID
                              order by time
                                 limit 3, 10000000)
                        t);

也在SQLFiddle中


为所有id执行此操作,或者仅在子查询中设置where时执行一次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
UPDATE TABLE
  LEFT JOIN (
              SELECT *
                FROM (
                       SELECT @rn:=if(@prv=id, @rn+1, 1) AS rId,
                              @prv:=id AS id,
                              TABLE.*
                         FROM TABLE
                         JOIN ( SELECT @prv:=0, @rn:=0 ) tmp
                        ORDER BY id, TIMESTAMP
                     ) a
               WHERE rid > 3
             ) ordered ON ordered.id = TABLE.id
   AND ordered.TIMESTAMP = TABLE.TIMESTAMP
   AND ordered.text = TIMESTAMP.text
   SET VALID = -1
 WHERE rid IS NOT NULL