Проблема с {country, state, city} заключается в том, что они кажутся потенциальным ключом для указанной таблицы. В SQL {страна, штат, город} не может быть кандидатным ключом (или даже первичным ключом), если штат (или страна) может отсутствовать или иметь значение NULL. (этого можно было бы избежать, разрешив для них пустую строку, которая отличается от NULL, но это было бы уродливым взломом, IMO) То же самое касается почтового индекса, который можно было бы превратить в ключ-кандидат, только добавив к нему country
. И оба могут отсутствовать, неизвестно или NULL.
Единственный способ обойти искалеченные ключи-кандидаты - это понизить их статус до (неуникальных) индексов и добавить суррогатный первичный ключ, как в:
CREATE TABLE cities
( city_id INTEGER NOT NULL PRIMARY KEY -- could be a serial ...
, country_name varchar -- you _could_ squeeze this out into a separate "countries" table
, state_name varchar -- you could even squeeze this out, but it would need a composite FK
, city_name varchar NOT NULL
);
CREATE TABLE adresses
( person_id INTEGER NOT NULL PRIMARY KEY -- could be a serial
, last_name varchar NOT NULL
, first_first_name varchar
, gender CHAR(1)
, dob DATE
, city_id INTEGER references cities(city_id) -- could be NOT NULL
);
WRT {city,state}
: вы можете выжать их в таблицу соединений (в основном это проблема BCNF, возможно, даже проблема 4NF, если все поля соединения не имеют NULLABLE), как в:
--
-- Plan B:
--
CREATE TABLE country2
( country_id INTEGER NOT NULL PRIMARY KEY -- could be a serial ...
, country_name varchar NOT NULL
, country_iso varchar
-- ...
, UNIQUE (country_name)
);
CREATE TABLE country_state2
( cs_id INTEGER NOT NULL PRIMARY KEY -- could be a serial ...
, country_id INTEGER NOT NULL REFERENCES country2(country_id)
, state_name varchar
);
CREATE TABLE cities2
( city_id INTEGER NOT NULL PRIMARY KEY -- could be a serial ...
, cs_id INTEGER REFERENCES country_state2(cs_id)
, city_name varchar NOT NULL
);
CREATE TABLE adresses2
( person_id INTEGER NOT NULL PRIMARY KEY -- could be a serial
, last_name varchar NOT NULL
, first_first_name varchar
, gender CHAR(1)
, dob DATE
, city_id INTEGER references cities2(city_id) -- could be NOT NULL
);
Стоит ли вам это делать - дело вкуса (см. Ответ @Joel Brown). Нормализация, безусловно, поможет в случае массовых операций по переименованию, таких как слияние муниципалитетов в OQ. Для небольших наборов адресов (до нескольких тысяч) дополнительная сложность, вероятно, будет стоить дороже, чем она получит. Эта сложность особенно дорого обходится интерфейсным приложениям, используемым для обслуживания данных. Для СУБД несколько объединений не будут стоить так много (для небольших размеров) и даже могут улучшить производительность (для больших размеров). Нормализация неплоха для производительности.
ОБНОВЛЕНИЕ (после комментария Майка Шерилла козла):
Если бы мы могли наложить NOT NULL
ограничений на {страну, штат, город} (или их идентификаторы), мы также могли бы наложить УНИКАЛЬНЫЕ ограничения на (составные) ключи-кандидаты, частью которых они являются: - - План C: - СОЗДАТЬ ТАБЛИЦУ country3 (country_id INTEGER NOT NULL PRIMARY KEY - может быть серийный номер ..., country_name varchar NOT NULL, country_iso varchar, UNIQUE (country_name));
CREATE TABLE country_state3
( cs_id INTEGER NOT NULL PRIMARY KEY -- could be a serial ...
, country_id INTEGER NOT NULL REFERENCES country3(country_id)
, state_name varchar NOT NULL
, UNIQUE (country_id,state_name)
);
CREATE TABLE cities3
( city_id INTEGER NOT NULL PRIMARY KEY -- could be a serial ...
, cs_id INTEGER NOT NULL REFERENCES country_state3(cs_id)
, city_name varchar NOT NULL
, UNIQUE (cs_id,city_name)
);
CREATE TABLE adresses3
( person_id INTEGER NOT NULL PRIMARY KEY -- could be a serial
, last_name varchar NOT NULL
, first_first_name varchar
, gender CHAR(1)
, dob DATE
-- allowing NULL here allows for 'embryonic' records without city/state/country info.
, city_id INTEGER references cities3(city_id)
);
Хотя это NOT NULL
ограничение позволит избежать дублирования в {city, state, country}, очевидно, что оно также наложит на них значение NOT NULL. Это может быть невозможно или недействительно в других странах (кроме Канады или США). В Нидерландах у нас нет state
или county
; у нас есть provincie
, который почти не используется (только для устранения неоднозначности, если необходимо). Аналогично для французского departements
, IIRC.
person
wildplasser
schedule
29.06.2013
Person
. Проблема, которая возникает, когда, скажем, химия получает новое здание отдельно от химического машиностроения. Как узнать, кто движется? - person HABO   schedule 01.07.2013