Удаление дубликатов строк внешнего ключа в базе данных MySQL

#mysql #sql #relational-database

#mysql #sql #реляционная база данных

Вопрос:

У меня есть таблица Stores и таблица Schools . Это отношение «один ко многим» — одно и то же хранилище может обслуживать несколько школ, но не наоборот.

Ранее при разработке я допустил ошибку, повторив одно и то же хранилище несколько раз в Stores базе данных. Я вставил строки, подобные:

 Store_ID| Store_URL
1       | http://sameurl.com
2       | http://sameurl.com
  

И тогда, если бы две разные школы были в одном и том же магазине, я бы ссылался 1 на одну школьную строку, а 2 на другую.

Я могу довольно легко идентифицировать дубликаты, используя GROUP BY on Store_URL и using COUNT() для идентификации дубликатов.

Трудная задача, стоящая передо мной, заключается в том, чтобы сделать все Schools возможное, чтобы не дублироваться Stores . Если я просто удалю дубликат Stores , у меня будет Schools который указывает на несуществующие строки.

Что я могу сделать, чтобы устранить дубликаты и заставить школы, которые используют одно и то же хранилище, указывать на одну и ту же Store строку?

Примечание: существуют тысячи школ и магазинов. Ручные решения не работают.

Комментарии:

1. В настоящее время я работаю над запросом, который соответствует моему текстовому предложению

2. Что касается части удаления, можете ли вы удалить любое хранилище без школы или только дублирующиеся записи хранилища?

3. Я не ожидаю, что будут какие-либо магазины без школ, хотя я ожидаю, что произойдет обратное

Ответ №1:

Предполагая, что в вашей School таблице есть store_ID из того, что вы сказали.

Я бы начал с определения для каждого дубликата, который store_ID вы хотите сохранить. Я также предположу, что вы хотите, чтобы это было наименьшее значение ID. Затем я бы обновил School s’ store_ID , чтобы он был MIN(store_ID) для текущего URL, который у них есть. После этого вы сможете свободно удалять лишние store_ID записи

Вот как я бы приступил к обновлению:

 UPDATE sch
SET sch.Store_ID = matcher.store_ID
FROM Schools AS sch
INNER JOIN Stores AS st ON sch.store_ID = st.store_ID
INNER JOIN
(
   SELECT MIN(st.store_id) AS store_ID, store_url
   FROM Schools AS sch
   INNER JOIN Stores AS st ON sch.store_ID = st.store_ID
   GROUP BY Store_URL
) AS matcher ON st.Store_URL = matcher.Store_Url
   AND st.Store_ID != matcher.store_ID
  

Если вы можете удалить магазины, у которых нет связанной школы, следующий запрос удалит лишние строки:

 DELETE FROM st
FROM Stores AS st
LEFT JOIN Schools AS sch ON st.Store_ID = sch.Store_Id
WHERE sch.Store_id IS NULL
  

Если вы хотите удалить только дубликаты записей хранилища, я бы рассмотрел этот запрос вместо приведенного выше:

 DELETE FROM st
FROM Stores AS st
INNER JOIN
(
   SELECT MIN(st.store_ID) store_Id, st.Store_Url
   FROM Stores AS st
   GROUP BY st.Store_URL
) AS useful ON st.Store_Url = useful.Store_URL
WHERE st.Store_ID != useful.store_Id
  

Комментарии:

1. Нужно посмотреть, как это работает, но я собираюсь использовать базовый подход. Спасибо

2. Нет проблем, я добавил запрос на удаление, который должен удалить только те записи, которые были дубликатами для вас.

3. Является ли повторение строки INNER JOIN Stores AS st ON sch.store_ID = st.store_ID в вашем первом запросе опечаткой? Кроме того, какова цель AND st.Store_ID != match.store_ID

Ответ №2:

Следующая инструкция update изменит значения в базе данных одной школы:

 UPDATE Schools SET store_id = 1 WHERE store_id = 2;
DELETE FROM Stores WHERE Store_ID = 2;
  

Комментарии:

1. Мне нужно сделать это для тысяч школ. Это нельзя сделать вручную следующим образом

2. сотни. ищу решение, подобное Адаму Венгеру, которое может сделать это за 1 запрос