Таблицы поиска дизайна базы данных - PullRequest
4 голосов
/ 17 сентября 2008

В настоящее время я пытаюсь улучшить дизайн устаревшей БД, и у меня следующая ситуация

В настоящее время у меня есть таблица SalesLead, в которой мы храним LeadSource.

Create Table SalesLead(
    ....
    LeadSource varchar(20)
    ....
)

Исходные источники хранятся в виде таблицы.

Create Table LeadSource (
    LeadSourceId int,   /*the PK*/
    LeadSource varchar(20)
)

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

Надеюсь, все стандартные вещи.

Вот моя проблема. Кажется, я не могу уйти от вопроса, что вместо того, чтобы писать

 SELECT * FROM SalesLead Where LeadSource = 'foo'

Что совершенно однозначно, теперь я должен написать

SELECT * FROM SalesLead where FK_LeadSourceID = 1

или

SELECT * FROM SalesLead 
INNER JOIN LeadSource ON SalesLead.FK_LeadSourceID = LeadSource.LeadSourceId 
where LeadSource.LeadSource = "foo"

Что сломается, если мы когда-либо изменим содержимое поля LeadSource.

В моем приложении, когда я хочу изменить значение LeadSource в SalesLead, я не хочу обновлять с 1 до 2 (например), так как я не хочу, чтобы разработчики помнили эти магические числа . Идентификаторы являются произвольными и должны быть сохранены.

Как мне удалить или отменить зависимость от них в коде моего приложения?

Редактировать Языки, которые будет поддерживать мое решение

  • .NET 2.0 + 3 (для чего стоит asp.net, vb.net и c #)
  • VBA (доступ)
  • дБ (MSSQL 2000)

Редактировать 2.0 Соединение в порядке, просто «foo» может измениться по запросу на «foobar», и я не хочу обрабатывать запросы.

Ответы [ 7 ]

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

Если вы хотите отменить нормализацию таблицы, просто добавьте столбец LeadSource (Varchar) в таблицу SalesLead вместо использования FK или ID.

С другой стороны, если ваш язык поддерживает структуры ENUM, «магические числа» должны быть безопасно сохранены в enum, чтобы вы могли:

SELECT * FROM SALESLEAD WHERE LeadSouce = (int) EnmLeadSource.Foo; //pseudocode

И ваш код будет иметь

public enum EnmLeadSource 
{
   Foo = 1,
   Bar = 2
}

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

Наилучшим подходом после нормализации, по-видимому, является использование структуры Enum. Он сохраняет код в чистоте, и вы всегда можете передавать перечисления по методам и функциям. (Я предполагаю, что .NET здесь, но и на других языках)

Обновление : Поскольку вы используете .NET, внутренний интерфейс БД не имеет значения, если вы строите запрос с помощью кода. Представьте себе эту функцию:

public void GiveMeSalesLeadGiven( EnmLeadSource thisLeadSource )
{
  // Construct your string using the value of thisLeadSource 
}

В таблице у вас будет столбец LeadSource (INT). Но тот факт, что он имеет 1,2 или N, не имеет значения для вас. Если вам позже потребуется изменить foo на foobar, это может означать, что:

1) Все «номер 1» должны быть номером «2». Вам придется обновить таблицу. 2) Или вам нужно, чтобы Foo теперь был номером 2, а столбец № 1. Вы просто меняете Enum (но убедитесь, что значения таблицы остаются неизменными).

Enum - очень полезная структура при правильном использовании.

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

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

Рассматривали ли вы просто не использовать искусственный ключ для таблицы LeadSource? Затем вы можете использовать LeadSource в качестве FK в SalesLead, что упрощает ваши запросы, сохраняя преимущества использования канонического набора значений (строки в LeadSource).

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

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

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

Здесь ложная дихотомия.

SELECT * FROM SalesLead 
INNER JOIN LeadSource ON SalesLead.FK_LeadSourceID = LeadSource.LeadSourceId 
where LeadSource.LeadSource = "foo"

не ломается больше, чем оригинал

SELECT * FROM SalesLead Where LeadSource = 'foo'

когда foo изменяется на foobar. Кроме того, если вы используете параметризованные запросы (и вы действительно должны это делать), вам не нужно ничего менять, когда foo меняется на foobar.

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

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

Похоже, что у вашего приложения есть "хорошо известные" источники информации, для которых вам нужно написать конкретные запросы. Если это так, то добавьте третье (уникальное) поле в таблицу LeadSource, которое включает в себя инвариантное «имя», которое вы можете использовать в качестве основы для запросов вашего приложения.

Это переносит бремя волшебства с магического числа, генерируемого БД (которое может варьироваться от установки к установке), на магическое имя, определенное системой (которое фиксируется проектом).

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

Если вы «улучшите дизайн», введя новые отношения / таблицы, вам наверняка понадобятся разные сущности. Если это так, вам нужно разобраться с их семантикой.

В предыдущем решении вы могли просто обновить имя LeadSource на то, что вы хотели в соответствующей строке SalesLead. Если вы обновите имя в своей новой структуре, вы сделаете это для всех строк SalesLead.

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

Если вам не нравится присоединиться, попробуйте SELECT * FROM SalesLead, где LeadSourceId IN (идентификатор SELECT FROM LeadSource, ГДЕ LeadSource = 'foo')

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

Я действительно не вижу твоей проблемы за объединением.

Естественно, запрос напрямую по FK_LeadSourceID неверен, но использование JOIN кажется правильным, поскольку я отлично маскирую изменение идентификаторов. Если, например, «foo» становится 3 за один день (и вы обновляете поле внешнего ключа), последний отображаемый вами запрос будет работать точно так же.

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

Или, если вы опасаетесь, что синтаксис объединения не интуитивен, всегда есть подвыбор ...

SELECT * FROM SalesLead where FK_LeadSourceID = 
         (SELECT LeadSourceID from LeadSource WHERE LeadSource = 'foo')

но не забудьте сохранить индекс на LeadSource.LeadSource - по крайней мере, если их много в таблице.

...