3

我有几组数据。每个组都有一些property字段。例如:

_________________________
| id  | value | property |  
--------------------------
| 1    |  2    |    3    |
--------------------------
| 2    |  2    |    3    |
--------------------------
| 3    |  2    |    3    |
--------------------------
| 4    |  2    |    4    |
-------------------------
| 5    |  2    |    4    |
--------------------------
| 6    |  2    |    4    |
--------------------------

如何更新由id ASCwith排序的两个字符串,以及由一个查询property = 3排序的 2 个字符串?id ASCproperty = 4

我想用 更新 3 行中的 2 行,用property = 3更新 3 行中的 2 行property = 4。例如:id 为 1 和 2 的行,以及 id 为 4 和 5 的行,即我希望通过一个查询
更新具有不同条件的数据组

4

3 回答 3

2

您可以使用计算的排名字段来做到这一点,例如 -

SELECT p1.*, COUNT(*) rank FROM properties p1
  LEFT JOIN properties p2
    ON p2.property = p1.property AND p2.id <= p1.id
  GROUP BY p1.property, p1.id

此查询将按属性返回具有行号的数据集:

+------+-------+----------+------+
| id   | value | property | rank |
+------+-------+----------+------+
|    1 |     2 |        3 |    1 |
|    2 |     2 |        3 |    2 |
|    3 |     2 |        3 |    3 |
|    4 |     2 |        4 |    1 |
|    5 |     2 |        4 |    2 |
|    6 |     2 |        4 |    3 |
+------+-------+----------+------+

然后你应该更新 rank < 3 的记录:

UPDATE properties p
  JOIN (SELECT p1.*, COUNT(*) rank FROM properties p1
          LEFT JOIN properties p2
            ON p2.property = p1.property AND p2.id <= p1.id
        GROUP BY p1.property, p1.id) r
  ON p.id = r.id
  SET p.value = 100 -- set new value here
  WHERE r.rank < 3
于 2012-08-13T14:31:22.683 回答
1

我假设您的意思是将您的两次更新限制为每行两行。您可以在更新语句中使用ORDER BY和:LIMIT

UPDATE yourtable
SET property = 'new_value'
WHERE value=2 AND property = 4
ORDER BY id ASC LIMIT 2


UPDATE yourtable
SET property = 'new_value'
WHERE value=2 AND property = 3
ORDER BY id DESC LIMIT 2

更新:

要将其强制到一个查询中,您需要JOIN针对一个子查询,该子查询检索要通过UNION. 我认为这是合法的:

UPDATE yourtable
  JOIN (
    (SELECT id FROM yourtable WHERE value=2 AND property=4 ORDER BY id ASC LIMIT 2)
    UNION ALL
    (SELECT id FROM yourtable WHERE value=2 AND property=3 ORDER BY id DESC LIMIT 2)
  ) updaterows ON yourtable.id = updaterows.id
SET property = 'new value'
于 2012-08-06T16:35:22.677 回答
1

这是解决方案,请参阅以下讨论:

update 
  t,
  (select GROUP_CONCAT(ids) as matching_ids from (
    select 
      SUBSTRING_INDEX(GROUP_CONCAT(id order by id), ',', 2) AS ids
    from
      t
    where
      property in (3,4)
    group by
      property
    ) s1
  ) s2
set value=12345
where 
  FIND_IN_SET(id, matching_ids) > 0
;

为了说明,假设您的表被称为t,并且初始状态是:

root@mysql-5.1.51> select * from t;
+----+-------+----------+
| id | value | property |
+----+-------+----------+
|  1 |     2 |        3 |
|  2 |     2 |        3 |
|  3 |     2 |        3 |
|  4 |     2 |        4 |
|  5 |     2 |        4 |
|  6 |     2 |        4 |
+----+-------+----------+

运行此查询的结果是:

root@mysql-5.1.51> select * from t;
+----+-------+----------+
| id | value | property |
+----+-------+----------+
|  1 | 12345 |        3 |
|  2 | 12345 |        3 |
|  3 |     2 |        3 |
|  4 | 12345 |        4 |
|  5 | 12345 |        4 |
|  6 |     2 |        4 |
+----+-------+----------+

查询的简要说明:

我使用该语句id为每个属性选择前两个s。SUBSTRING_INDEX(GROUP_CONCAT(id order by id), ',', 2)

我结合上述使用GROUP_CONCAT(ids) as matching_ids来获得所有有效id的s。

最后,我更新了表中所有id在组合matching_ids文本中的行。

笔记:

  • 您应该验证您的group_concat_max_len变量是否足够长。默认为1024。无论如何,您很可能希望拥有数百万个(不管我的回答如何)。

  • 查询远非最佳。它回答了您的问题,但您无法在此处找到最佳查询。

  • 包含两个或三个查询的事务很可能会更好。

祝你好运!

于 2012-08-15T15:11:09.057 回答