Mysql按组进程处理数据

时间:2012-08-06 16:29:18

标签: mysql

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

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

如何通过id ASC更新由property = 3排序的两个字符串,并通过一个查询更新id ASCproperty = 4 排序的2个字符串?

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

3 个答案:

答案 0 :(得分: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

此查询将返回带有row-number by属性的数据集:

+------+-------+----------+------+
| 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 |
+------+-------+----------+------+

然后你应该更新排名&lt;的记录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

答案 1 :(得分:1)

我假设您的意思是将两个更新限制为每行两行。您可以在更新语句中使用ORDER BYLIMIT

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检索要更新的ID的子查询。我认为这是合法的:

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'

答案 2 :(得分: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语句为每个属性选取前两个SUBSTRING_INDEX(GROUP_CONCAT(id order by id), ',', 2)

我使用GROUP_CONCAT(ids) as matching_ids结合上述内容以获取所有有效的id

最后,我更新表格中id在合并matching_ids文字内的所有行。

备注:

  • 您应该验证group_concat_max_len变量足够长。默认值为 1024 。无论如何,你很可能想要数百万(无论我的答案如何)。

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

  • 对于包含两个或三个查询的交易,您最好的情况更好。

祝你好运!