Исправление плохого дизайна базы данных BAD, когда данные в системе - PullRequest
7 голосов
/ 17 сентября 2008

Я знаю, что это не вопрос ... во всяком случае, ЗДЕСЬ вопрос.

Я унаследовал базу данных с 1 (одной) таблицей, которая выглядит примерно так. Его цель - записать, какие виды встречаются в различных (200 странных) странах.

ID 
Species
Afghanistan
Albania
Algeria
American Samoa
Andorra
Angola
....
Western Sahara
Yemen
Zambia
Zimbabwe

Пример данных будет примерно таким

id Species Afghanistan Albania American Samoa
1  SP1         null     null        null
2  SP2          1         1         null
3  SP3         null      null         1

Мне кажется, что это типичная ситуация для многих, и я хочу 3 таблицы. Виды, Страна и ВидыFoundInCountry

Таблица ссылок (SpeciesFoundInCountry) будет иметь внешние ключи в таблицах видов и стран.

(Сложно нарисовать диаграмму!)

Species
SpeciesID  SpeciesName

Country
CountryID CountryName

SpeciesFoundInCountry
CountryID SpeciesID

Есть ли волшебный способ, которым я могу сгенерировать оператор вставки, который будет получать CountryID из новой таблицы Country на основе имени столбца и SpeciesID, где в исходной мега таблице есть 1?

Я могу сделать это для одной страны (это выбор, чтобы показать, что я хочу)

SELECT Species.ID, Country.CountryID
FROM Country, Species
WHERE (((Species.Afghanistan)=1)) AND (((Country.Country)="Afghanistan"));

(мега стол называется видом)

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

Есть ли способ сделать это в SQL?

Полагаю, я могу ИЛИ загрузить свои предложения where вместе и написать скрипт для создания sql, хотя это выглядит не элегантно!

Есть мысли (или требуется уточнение)?

Ответы [ 20 ]

8 голосов
/ 17 сентября 2008

Я бы использовал скрипт для генерации всех отдельных запросов, так как это одноразовый процесс импорта.

Некоторые программы, такие как Excel, способны смешивать разные измерения данных (сравнивая имена столбцов с данными внутри строк), но реляционные базы данных редко бывают.

Однако вы можете обнаружить, что некоторые системы (например, Microsoft Access, на удивление) имеют удобные инструменты, которые вы можете использовать для нормализации данных. Лично я бы сочинил сценарий быстрее, но ваши относительные навыки работы с Access и сценариями могут отличаться от моих.

8 голосов
/ 17 сентября 2008

Почему вы хотите сделать это в SQL? Просто напишите небольшой скрипт, который выполняет преобразование.

3 голосов
/ 17 сентября 2008

Когда я сталкиваюсь с ними, я пишу скрипт для преобразования, а не пытаюсь сделать это в SQL. Это обычно намного быстрее и проще для меня. Выберите любой язык, с которым вам удобно.

2 голосов
/ 17 сентября 2008

Если бы это был SQL Server, вы бы использовали команды Unpivot, но, глядя на назначенный вами тег, он для доступа - я прав?

Хотя в доступе есть команда поворота , обратного оператора нет.

Похоже, это можно сделать с помощью сложного соединения. Посмотрите эту интересную статью , чтобы узнать, как отключить команду выбора.

1 голос
/ 23 сентября 2008

Если мне когда-нибудь понадобится создать набор похожих SQL-операторов и выполнить их все, я часто нахожу, что Excel очень удобен. Возьмите ваш оригинальный запрос. Если у вас есть список стран в столбце A и оператор SQL в столбце B, форматированный как текст (в кавычках) со вставленными ссылками на ячейки, где страна отображается в sql

например. = "INSERT INTO new_table SELECT ... (разновидности." & A1 & ") = ...));"

, затем просто скопируйте формулу вниз, чтобы создать 200 различных операторов SQL, скопируйте / вставьте столбец в редактор и нажмите F5. Конечно, вы можете сделать это с любым количеством переменных.

1 голос
/ 17 сентября 2008

Извините, я мало занимался программированием Access, но могу предложить несколько советов, которые должны помочь.

Сначала давайте пройдемся по проблеме. Предполагается, что вам обычно нужно создать несколько строк в SpeciesFoundInCountry для каждой строки в исходной таблице. Другими словами, виды, как правило, находятся в более чем одной стране. Это на самом деле легко сделать с помощью декартового произведения, объединение без критериев объединения.

Чтобы сделать декартово произведение, вам нужно создать таблицу Страна. Таблица должна иметь идентификатор страны от 1 до N (N - количество уникальных стран, 200 или около того) и название страны. Чтобы упростить жизнь, просто используйте цифры от 1 до N в порядке столбцов. Это сделало бы Афганистан 1 и Албанию 2 ... Зимбабве Н. Вы должны быть в состоянии использовать системные таблицы для этого.

Затем создайте таблицу или представление из исходной таблицы, которая содержит виды и жало с 0 или 1 для каждой страны. Вам нужно будет преобразовать значение NULL, а не NULL, в текст 0 или 1 и объединить все значения в одну строку. Описание таблицы и текстовый редактор с регулярными выражениями должны упростить эту задачу. Сначала поэкспериментируйте с одним столбцом, а после того, как он заработает, отредактируйте представление / вставку создания со всеми столбцами.

Затем объедините две таблицы без критериев объединения. Это даст вам запись для каждого вида в каждой стране, вы почти там.

Теперь все, что вам нужно сделать, это отфильтровать недопустимые записи, они будут иметь ноль в соответствующем месте в строке. Так как столбец country_code таблицы страны содержит местоположение подстроки, все, что вам нужно сделать, это отфильтровать записи, где он равен 0.

where substring(new_column,country_code) = '1'

Вам все еще нужно будет создать таблицу видов и присоединиться к ней

where a.species_name = b.species_name

a и b - псевдонимы таблиц.

Надеюсь, эта помощь

1 голос
/ 17 сентября 2008

OBTW,

Если у вас есть запросы, которые уже выполняются к старой таблице, вам нужно будет создать представление, которое реплицирует старые таблицы с использованием новых таблиц. Вам нужно будет сделать группу, чтобы денормализовать таблицы.

Сообщите своим пользователям, что старая таблица / представление не будет поддерживаться в будущем, и все новые запросы или обновления старых запросов должны будут использовать новые таблицы.

1 голос
/ 17 сентября 2008

Я бы использовал запрос Union, очень приблизительно:

Dim db As Database
Dim tdf As TableDef

Set db = CurrentDb

Set tdf = db.TableDefs("SO")

strSQL = "SELECT ID, Species, """ & tdf.Fields(2).Name _
    & """ AS Country, [" & tdf.Fields(2).Name & "] AS CountryValue FROM SO "

For i = 3 To tdf.Fields.Count - 1
    strSQL = strSQL & vbCrLf & "UNION SELECT ID, Species, """ & tdf.Fields(i).Name _
    & """ AS Country, [" & tdf.Fields(i).Name & "] AS CountryValue FROM SO "
Next

db.CreateQueryDef "UnionSO", strSQL

После этого у вас будет представление, которое можно добавить к вашему новому дизайну.

1 голос
/ 17 сентября 2008

Когда я прочитал название «плохой плохой дизайн базы данных», мне было интересно узнать, насколько он плох. Вы меня не разочаровали:)

Как уже упоминалось, сценарий будет самым простым способом. Это можно сделать, написав около 15 строк кода на PHP.

SELECT * FROM ugly_table;
while(row)
foreach(row as field => value)
if(value == 1)
SELECT country_id from country_table WHERE country_name = field;

if(field == 'Species')
SELECT species_id from species_table WHERE species_name = value;

INSERT INTO better_table (...)

Очевидно, что это псевдокод, и он не будет работать как есть. Вы также можете заполнить таблицу стран и видов на лету, добавив здесь операторы вставки.

1 голос
/ 17 сентября 2008

Извините, но парсер кровавых сообщений удалил пробелы и форматирование в моем сообщении. Это усложняет чтение журнала.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...