MySQL查询更新除最新行之外的所有“重复”行

时间:2014-10-21 19:52:08

标签: mysql group-by max rdbms partition-by

... SO

我有一张桌子(让我们称之为数据位置)就像......

Data Location ID    Data ID    Location Type    Location URL   Status    Date
1                   1          Foo              foo/3          Valid     10-21-2014
2                   1          Bar              bar/1          Valid     10-21-2014
3                   1          Foo              foo/2          Valid     03-20-2013
4                   1          Foo              foo/1          Valid     12-01-2010

......等等。该表有许多不同的数据ID(为简单起见,我没有显示它们)。我们的想法是,对于给定的数据ID和位置类型,应该只有1个有效条目,如上所示,数据ID 1的所有Foo位置都是有效的(foo / 1,foo / 2,foo / 3)

有人可以帮我构建一个查询,将所有重复记录(相同的数据ID和位置类型)状态列更新为无效,除了最新的条目。我有一个查询可以识别符合重复条件的行,但我不确定如何将group by与max(或不是max?)和update进行组合。似乎分区可能是方式,但我对查询有点生疏,所以我感谢任何帮助。所以对于上面的数据,我希望结果是......

Data Location ID    Data ID    Location Type    Location URL   Status    Date
1                   1          Foo              foo/3          Valid     10-21-2014
2                   1          Bar              bar/1          Valid     10-21-2014
3                   1          Foo              foo/2          Invalid   03-20-2013
4                   1          Foo              foo/1          Invalid   12-01-2010

...提前致谢!

3 个答案:

答案 0 :(得分:2)

您可以使用一个UPDATE语句:

UPDATE Data_Location u
INNER JOIN (
  SELECT `Data ID`, `Location Type`, MAX(`Date`) AS max_date
  FROM Data_Location
  GROUP BY `Data ID`, `Location Type`
) t ON u.`Data ID` = t.`Data ID` 
   AND u.`Location Type` = t.`Location Type`
SET u.Status = 'Invalid'
WHERE u.`Date` <> t.max_date

SQL Fiddle

上进行测试

答案 1 :(得分:1)

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(ID    INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,Data_ID INT  NOT NULL
,Location_Type    VARCHAR(5) NOT NULL
,Status    VARCHAR(12) NOT NULL
);

INSERT INTO my_table VALUES
(1,1,'Foo','Valid'),
(2,1,'Bar','Valid'),
(3,1,'Foo','Valid'),
(4,1,'Foo','Valid');     

SELECT * FROM my_table;
+----+---------+---------------+--------+
| ID | Data_ID | Location_Type | Status |
+----+---------+---------------+--------+
|  1 |       1 | Foo           | Valid  |
|  2 |       1 | Bar           | Valid  |
|  3 |       1 | Foo           | Valid  |
|  4 |       1 | Foo           | Valid  |
+----+---------+---------------+--------+

UPDATE my_table x 
  JOIN my_table y 
    ON y.data_id = x.data_id 
   AND y.location_type = x.location_type 
   AND y.id < x.id 
   SET x.status = 'Invalid';

SELECT * FROM my_table;
+----+---------+---------------+---------+
| ID | Data_ID | Location_Type | Status  |
+----+---------+---------------+---------+
|  1 |       1 | Foo           | Valid   |
|  2 |       1 | Bar           | Valid   |
|  3 |       1 | Foo           | Invalid |
|  4 |       1 | Foo           | Invalid |
+----+---------+---------------+---------+


mysql>

答案 2 :(得分:0)

  • 使用UPDATE table SET status = 'invalid'
  • 之类的简单查询将所有这些设置为无效
  • 然后执行另一个查询,按数据ID和位置类型对行进行分组,并按ID按降序排序。将所选行设置为有效。我不确定我下面提供的两个查询是否可以合并,我现在没有测试环境,但它会这样工作:

-

$query = $yourPDO->prepare('SELECT id FROM table ORDER BY id DESC GROUP BY data_id, location_type');
$query->execute();
$results = $query->fetchAll(PDO::FETCH_OBJ);

$ids = [];

// not sure if there is an array_* function for this functionality:
foreach ($results as $row)
{
    $ids[] = $row->id;
}

$yourPDO->prepare('UPDATE table SET status = "valid" WHERE id IN (' . implode(', ', $ids) . ')');