Ответ 1
Хорошо; поэтому у вас есть несколько таблиц, происходящих из разных источников, каждый из которых реализует один и тот же объект (Продукт) со своей собственной логической структурой. Любая заданная запись может существовать в нескольких таблицах, и ваша задача состоит в том, чтобы согласовать эти разные источники данных, используя какой-либо ручной процесс для определения того, какие записи одинаковы/идентичны между таблицами.
Это похоже на процесс, который мы проводим в Cal/EPA для согласования данных из разных источников при создании инвентаризации загрязнения воздуха в масштабе штата. Эти источники включают в себя несколько различных групп моделирования, каждая из которых работает с отдельным набором входных и выходных параметров; прямые измерения с станций мониторинга; ежегодные отчеты локальных и муниципальных учреждений; и в некоторых случаях данные поступают непосредственно нам частными лицами и предприятиями. Эти данные поступают к нам во многих разных форматах, и большая часть их перекрывается.
Я не буду утомлять вас деталями нашего процесса примирения, но я могу рассказать вам кое-что из того, что я узнал от него, и предложить подход, который может сработать для вас.
Во-первых, сборка перекрывающихся данных, которая существует во многих разных форматах, отстой. Наши рабочие места были бы намного проще, если бы все использовали одни и те же структуры таблиц и оставались друг от друга. Тем не менее, это реальность, с которой нам приходится иметь дело; вот почему у нас есть рабочие места. Различные организации и отдельные лица работают по-разному, периоду, и большую часть времени у вас не будет возможности изменить способ работы.
Вам нужен план, иначе будут сделаны ошибки - не случайные ошибки, а постоянные. Один широкий подход, который вы можете предпринять, заключается в следующем: я буду принимать данные из всех этих источников во всех этих форматах и помещать их в промежуточную базу данных, где я буду манипулировать и агрегировать и измельчать, удалять и калечить данные по мере необходимости, чтобы поместить его в мой блестящая, хорошо управляемая база данных, где есть только одна физическая модель, и все замечательно. Затем я могу забыть обо всех невыразимых вещах, которые я сделал с данными, чтобы они были в нем в первую очередь, и жизнь будет замечательной... пока я не буду делать это снова и снова. Это называется ETL, что означает Извлечь, Преобразовать, Загрузить или, возможно, Entrap, Torture, Lobotomize в зависимости от того, насколько вы веселитесь. Вы можете прочитать об этом в Википедии, если хотите (или здесь, на SO, или здесь, на DBA.SE, или в это руководство от компании, которая знает что-то или другое о пытках).
Хорошая вещь о ETL заключается в том, что вы попадаете туда, где чувствуете себя хорошо. Не очень приятная вещь в ETL заключается в том, что, преобразовывая данные в соответствии с вашими конкретными потребностями, вы часто теряете определенную степень детализации или полезности, которые присутствовали в источнике. С другой стороны, если вы создаете очень обобщенную модель данных, чтобы как можно больше извлекать такие исходные данные и избегать деструктивных преобразований, вы получаете высоко обобщенную модель данных, что подразумевает большую документацию и обслуживание, даже если ваш модель идеальна, которой она никогда не бывает.
Теперь, похоже, вы либо не желаете, либо не можете преобразовать исходные данные в соответствии с разумно сфокусированной моделью. И вы не должны втискивать все в одну таблицу, полную повторяющихся столбцов и NULL, чтобы ваш быстрый спуск в безумие не прерывался видениями Ктулху в его доме в R'lyeh:
+-----+---------+------------+---------+-----------------+-------------+-----+
| id | sup1_id | sup1_color | sup2_id | sup2_color | sup2_weight | ... |
+-----+---------+------------+---------+-----------------+-------------+-----+
| 1 | 7124 | brn | 93 | Burnt Sienna | 0.65 | ... |
| 2 | 415 | yel | 8552 | Bananas Foster | 12.50 | ... |
| 3 | NULL | NULL | 51 | Mostly Red | 2.00 | ... |
| 4 | 159 | wht | NULL | NULL | NULL | ... |
| 5 | NULL | NULL | NULL | NULL | NULL | NULL NULLNULLNULLUNNLUNUL gratuitous Unicode diacritics, you get the idea
Это вообще не относится к реляционной базе данных; это парадигма плоского файла/таблицы, которая должна быть ограничена не-базами данных, такими как Excel. (Или доступ. Zing!)
Что вам осталось, если вам нужно сохранить разрозненные таблицы в их различных формах, но все же хотите связать их друг с другом и сохранить какую-то "основную" запись, создает дополнительные таблицы, чтобы охарактеризовать эти отношения и сохраните свой "один ключ, чтобы править ими всеми". Теперь мы направляемся в сторону разговоров о подтипах и ролях. У вас есть один объект (Продукт), который представлен различными способами; если каждый экземпляр продукта существует только в одном представлении, то вы имеете дело с подтипами сущностей. В случае, когда есть перекрытие, как здесь, лучше подумать о ролях, которые экземпляры могут взять на себя с каждым поставщиком. Здесь приведен пример из Data Modeling, Руководство для начинающих:
Ваш "главный" идентификатор и любая связанная информация будут принадлежать левому полю, которое я просто позвоню в продукт. Здесь вы хотите хранить атрибуты, которые всегда будут одинаковыми для данного продукта, независимо от поставщика; или "официальная" версия атрибута, который, как вы знаете, отличается от поставщиков, если таковой требуется. Например, если вы являетесь производителем, ваш MSRP для продукта не зависит от розничного продавца, несущего продукт; он должен быть в главной таблице. Он также может служить "официальной" ценой, в отличие от различных ценовых цен, связанных с разными розничными торговцами.
Ваши различные таблицы поставщиков справа. Это роли, которые приобретает продукт; здесь будет храниться любая информация, которую вы хотите изменить от поставщика к поставщику (в вашем примере, цвет продукта), или это связано с некоторыми поставщиками, а не с другими (в вашем примере, весом). Поскольку между продуктами и ролями существует много-много взаимосвязей, вы добавляете таблицу соединений между ними, где назначаются роли; вам не нужно иметь даты в вашей таблице соединений, как в приведенном выше изображении, если вы не храните историю, но это пример, когда информация о назначении роли была бы подходящей для хранения в таблице соединений.
Поскольку вы указали, что вам нужно связать записи из таблиц поставщика после их вставки, через ваш ручной процесс, ваш рабочий процесс под этим подходом, вероятно, будет примерно таким:
- Записи вставляются в различные таблицы поставщиков.
- Вы заметили, что новые записи были вставлены (здесь, где триггер может быть полезен).
- Используя ваш ручной мануальный процесс, вы определяете, действительно ли каждая новая запись существует или не существует в Продукте.
- Всякий раз, когда новая запись от поставщика не существует в Product, вы вставляете новую строку в Продукт, чтобы однозначно идентифицировать (и, возможно, охарактеризовать) этот элемент.
- Вы вставляете новую строку в таблицу соединений для каждой новой записи от поставщика, связывая уникальную запись для этого элемента с дополнительной информацией, характеризующей ее в своей роли с этим поставщиком.
Обратите внимание, что, поскольку ваши внешние ключи находятся в таблице соединений, возможно наличие продуктов без роли/поставщика и поставщиков, не имеющих продуктов. Что касается соблюдения рабочего процесса и избежания ошибок, если вы не готовы предоставить нам гораздо больше информации о вашем процессе для связывания продуктов между таблицами поставщиков, я могу предложить лучше всего использовать триггеры AFTER INSERT
на каждой из таблиц поставщика поместить имя таблицы и PK строки в таблицу, которая отслеживает новые продукты, пока они не пройдут процесс ручного связывания, и удалите эти строки по ходу процесса ручного связывания.
Вы можете использовать другой триггер в таблице соединений, чтобы очистить таблицу новых/несвязанных продуктов, но он более рискован, чтобы иметь триггер, обновляющий или удаляющий строки. Фактически, если вы можете заполнить таблицу новых/несвязанных продуктов, используя логику приложения вместо триггеров, это может быть предпочтительнее. Вы можете прочитать в блоге Триггеры, которые считаются вредными, считаются вредоносными для продуманного анализа обеих сторон триггерных дебатов, хотя это не относится к MySQL.