Как обновить несколько дубликатов с разными значениями в одной таблице?
В таблице, в которой я имею дело, есть несколько строк, которые имеют одинаковые значения для lat
и lon
. Пример показывает, что 1
, 3
, 5
имеют одинаковое расположение, но атрибут name
отличается. hash
построен из name
, lat
и lon
и поэтому отличается.
BEFORE:
id | name | lat | lon | flag | hash
----+------+-----+-----+------+------
1 | aaa | 16 | 48 | 0 | 2cd <-- duplicate
2 | bbb | 10 | 22 | 0 | 3fc
3 | ccc | 16 | 48 | 0 | 8ba <-- duplicate
4 | ddd | 10 | 23 | 0 | c33
5 | eee | 16 | 48 | 0 | 751 <-- duplicate
Мне нужно идентифицировать "дубликаты" в этой таблице и вы хотите назначить флаг 1
(primary) одному из них и флаг 2
(вторичный) для других. Не важно, какой "дубликат" помечен как первичный.
AFTER:
id | name | lat | lon | flag | hash
----+------+-----+-----+------+------
1 | aaa | 16 | 48 | 1 | 2cd <-- updated
2 | bbb | 10 | 22 | 0 | 3fc
3 | ccc | 16 | 48 | 2 | 8ba <-- updated
4 | ddd | 10 | 23 | 0 | c33
5 | eee | 16 | 48 | 2 | 751 <-- updated
Я начал экспериментировать с INNER JOIN
вдохновленным этим сообщением, и это визуальное описание. С этим я могу назначить один и тот же флаг всем дубликатам.
UPDATE table t1
INNER JOIN table_name t2
ON
t1.lat = t2.lat
AND t1.lon = t2.lon
AND t1.hash != t2.hash
SET
t1.flag = 2;
Я также тестировал LEFT OUTER JOIN
с WHERE t2.id IS NULL
, который мог работать, когда есть только две строки. Однако я не могу думать, как JOIN
должен работать с более двух дубликатов. Марк Харрисон также предполагает, что вы присоединяетесь к колонкам без дубликатов в начале своего сообщения, которые звучат так, как будто это не очень хорошая идея.
Я использую MySQL, если это интересно.
Ответы
Ответ 1
Не уверен, что это очень эффективно, но работает только в одном запросе:
UPDATE t
JOIN (
SELECT MAX(t.id) AS maxid, lat, lon
FROM t
JOIN t AS duplicates
USING (lat, lon)
GROUP BY lat, lon
HAVING COUNT(*) > 1
) AS maxima USING (lat, lon)
SET flag = IF(id = maxid, 1, 2);
Ответ 2
Предполагая, что вы хотите, чтобы все канонические записи имели flag=1
(а не только те записи, которые имеют дубликаты), вы можете сделать:
UPDATE table t1
SET t1.flag = 1
WHERE t1.id in (
SELECT min(id)
FROM table t2
WHERE t1.lat = t2.lat
AND t1.lon = t2.lon
);
UPDATE table
SET flag = 2
WHERE flag is null;
COMMIT;
Ответ 3
Вы можете сделать это в два этапа:
update table t1 set flag = 2 where id in
(select a.id
from
t1 a
join t1 b on (b.lon = a.lon and b.lat = a.lat));
update table t1 set flag = 1 where id in
(select a.id
from t1 a
where a.flag = 2 and a.id =
(select min(b.id) from t1 b where b.lon = a.lon and b.lat = a.lat)
);
Это должно использоваться как вдохновение, а не как Евангелие (это, вероятно, неправильно):)