Реляционная модель и запросы, которые естественным образом возвращают повторяющиеся строки

Обычно считается, что в реляционной модели:

  1. Каждая реляционная операция должна давать отношение.
  2. Отношения, будучи наборами, не могут содержать повторяющиеся строки.

Представьте себе отношение "ПОЛЬЗОВАТЕЛИ", которое содержит следующие данные.

ID FIRST_NAME LAST_NAME
 1 Mark       Stone
 2 Jane       Stone
 3 Michael    Stone

Если кто-то запускает запрос select LAST_NAME from USERSтипичная база данных вернет:

LAST_NAME
Stone
Stone
Stone

Поскольку это не отношение - поскольку оно содержит повторяющиеся строки - что должна возвращать идеальная СУБД?

5 ответов

Решение

"Но некоторая информация потеряна - что есть 3 пользователя с этой фамилией".

Если вас интересует количество пользователей с таким именем, то запрос вашего примера - это не тот вопрос, который вам следует задавать.

Запрос вашего примера даст ответ на вопрос "Каковы все фамилии, так что существует пользователь с такой фамилией?".

Если вопрос, который вы хотите задать, это "сколько пользователей с именем" Камень "", то запрос, который вы должны отправить, - это "Выбрать количество (...) из пользователей, где last_name =" Камень ";

Проекция всегда "теряет" информацию. Информация, которая связана с атрибутами, которые проецируются. Я не понимаю, как известное свойство полезного реляционного оператора можно объяснить как аргумент против этого оператора.

В СУБД реляционная проекция только на столбец с фамилией возвращает только набор кортежей с различными значениями фамилии. Там не было бы дубликатов кортежей.

В SQL верно, что вы получите дубликаты, если вы не укажете ключевое слово DISTINCT. Это связано с тем, что SQL не является по-настоящему реляционным языком, в том числе потому, что таблицы SQL и табличные выражения не являются правильными отношениями. СУБД SQL не является СУБД.

"что должна вернуть идеальная СУБД?"

Как указал Дэвид, он должен возвратить (в вашем примере) одну строку.

СУБД SQL является только реляционной, если она обрабатывает каждый SELECT, как если бы запросили SELECT DISTINCT. (Но есть несколько крошечных дополнительных условий, которые также должны быть выполнены.)

Причина этого в том, что "значение" этой единственной строки таково: "Существует такой пользователь, у которого есть first_name, у него есть ID, а его last_name -" Stone "".

Нет никакой логической необходимости повторять это утверждение во второй раз. Авторитетная ссылка, о которой вы просили, - это сам Тед Кодд: "Если что-то верно, то повторение дважды не сделает его более правдивым".

Я не уверен, что вижу проблему с возвращенными значениями. Есть три записи, которые содержат "Камень" для LAST_NAME, Это было бы очевидно, если бы FIRST_NAME или же ID был включен в запрос, но это не так. Обычно DISTINCT ключевое слово используется, чтобы обработать это и гарантировать, что не будет дубликатов.

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

Я бы сказал, что ваш исходный запрос не возвращал повторяющиеся строки. Он возвратил 3 отдельные строки данных из базы данных, в которую вы включили только колонку с фамилией. Я бы сказал, что ваш вопрос сформулирован неправильно, и, следовательно, почему СУБД функционируют так, как они это делают (я также утверждаю, что это правильно).

Чтобы перевести ваш запрос:

выберите LAST_NAME из USERS

на английский, это будет:

"скажи мне фамилию всех пользователей"

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

Если бы вы хотели задать вопрос: "Каковы разные фамилии учеников в классе", он не стал бы перечислять дублирующиеся имена. Однако это то, что существует ключевое слово "DISTINCT".

Таким образом, запрос будет:

выберите отдельного пользователя LAST_NAME из USERS

И если вас на самом деле интересовало количество уникальных фамилий на английском языке, то есть "Сколько разных фамилий у учеников в классе" или используйте ваш пример:

выберите количество (отличное от LAST_NAME) от USERS

тогда как: выберите количество (LAST_NAME) из USERS

будет означать по-английски: "Сколько человек в классе имеют фамилию?"

Другие вопросы по тегам