道歉,如果这已在其他地方得到解答,我只是没有看到它;这是我发现的最接近的,但它并不是我想要做的。
MySQL - updating all records to match max value in group
我在生产Web服务器上有一个表,大约有15,000行。有许多记录与另一个记录共享item_name,但item_meters是(通常但不总是)每行的唯一值。 item_id始终是唯一的。目前,每条记录的值都为" 0"在item_flag列中。
我想更新每个item_name组中具有最大item_meters值的所有记录,以使item_flag值为" 1"。
以下是按item_id ASC排序的表格的简化版本:
----------------------------------------------
mytable
----------------------------------------------
item_id | item_name | item_meters | item_flag
--------+-----------+-------------+-----------
001 | aaa | 224 | 0
002 | aaa | 359 | 0
003 | aaa | 456 | 0
004 | bbb | 489 | 0
005 | bbb | 327 | 0
006 | bbb | 215 | 0
007 | ccc | 208 | 0
008 | ccc | 756 | 0
009 | ccc | 756 | 0
--------+-----------+-------------+-----------
期望的结果将是" 1"在每个" aaa"的item_flag列中拥有最大的item_meters,每个" bbb"拥有最大的item_meters,每个" ccc"拥有最大的item_meters等等:
----------------------------------------------
mytable
----------------------------------------------
item_id | item_name | item_meters | item_flag
--------+-----------+-------------+-----------
001 | aaa | 224 | 0
002 | aaa | 359 | 0
003 | aaa | 456 | 1
004 | bbb | 489 | 1
005 | bbb | 327 | 0
006 | bbb | 215 | 0
007 | ccc | 208 | 0
008 | ccc | 756 | 1
009 | ccc | 756 | 0
--------+-----------+-------------+-----------
(如果有2个或更多记录具有相同的item_name 和相同的item_meters(例如上面的item_id 008和009),则所需的结果将是具有数字较低的item_id的记录( item_id始终是唯一的,item_flag值为" 1"而具有数字更高的item_id的行仍然具有item_flag值" 0")
另外值得注意的是,即使此数据库在生产Web服务器后面运行,每天都会添加新行,但每次添加新行时都不需要更新表。无论以后是否在参数之外添加新行,它都只需要一次。我提到这个的原因是因为执行速度不是一个大问题,因为查询只会被执行一次。
提前谢谢!如果我能以任何方式提供更多信息或澄清我的问题,请告诉我。
答案 0 :(得分:2)
我采取的方法是首先编写一个查询(SELECT语句),它将返回我们想要更新的行的item_id
值。
作为起点,获取item_meters
的最大值,这是一个简单的查询:
SELECT m.item_name
, MAX(m.item_meters) AS max_item_meters
FROM my_table m
GROUP BY m.item_name
我们可以将该查询用作另一个查询中的内联视图,以便为每个item_id
item_name
SELECT MIN(o.item_id) AS min_item_id
FROM ( SELECT m.item_name
, MAX(m.item_meters) AS max_item_meters
FROM my_table m
GROUP BY m.item_name
) n
JOIN my_table o
ON o.item_name = n.item_name
AND o.item_meters = n.max_item_meters
GROUP BY o.item_name, o.item_meters
我们可以将该查询用作内联视图,以获取与我们返回的item_id
值相关联的整行...
SELECT t.item_id
, t.item_name
, t.item_meters
, t.item_flag
FROM my_table t
JOIN ( SELECT p.min_item_id
FROM ( SELECT MIN(o.item_id) AS min_item_id
FROM ( SELECT m.item_name
, MAX(m.item_meters) AS max_item_meters
FROM my_table m
GROUP BY m.item_name
) n
JOIN my_table o
ON o.item_name = n.item_name
AND o.item_meters = n.max_item_meters
GROUP BY o.item_name, o.item_meters
) p
) q
ON q.min_item_id = t.item_id
SELECT查询工作后,将其转换为UPDATE语句...将SELECT ... FROM替换为UPDATE,并添加SET子句。 (有时,将内联视图包装在另一个SELECT中是必要的,以避免MySQL错误地禁止对我们正在更新的表的引用。)
UPDATE my_table t
JOIN ( SELECT p.min_item_id
FROM ( SELECT MIN(o.item_id) AS min_item_id
FROM ( SELECT m.item_name
, MAX(m.item_meters) AS max_item_meters
FROM my_table m
GROUP BY m.item_name
) n
JOIN my_table o
ON o.item_name = n.item_name
AND o.item_meters = n.max_item_meters
GROUP BY o.item_name, o.item_meters
) p
) q
ON q.min_item_id = t.item_id
SET t.item_flag = '1'
如果目的不是更新现有表,而是返回结果集,我们可以编写查询并对同一个内联视图执行外连接,并为item_flag
返回0或1 ,测试item_id
是否匹配我们想要标记为1 ...
SELECT t.item_id
, t.item_name
, t.item_meters
, IF(q.min_item_id IS NULL,0,1) AS `item_flag`
FROM my_table t
LEFT
JOIN ( SELECT p.min_item_id
FROM ( SELECT MIN(o.item_id) AS min_item_id
FROM ( SELECT m.item_name
, MAX(m.item_meters) AS max_item_meters
FROM my_table m
GROUP BY m.item_name
) n
JOIN my_table o
ON o.item_name = n.item_name
AND o.item_meters = n.max_item_meters
GROUP BY o.item_name, o.item_meters
) p
) q
ON q.min_item_id = t.item_id