Вопрос MySQL. Как обрабатывать несколько типов пользователей - одну таблицу или несколько?

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

Как обычно обрабатывается эта ситуация?

Спасибо!

Ответ 1

Ваши инстинкты не создают большую таблицу с большим количеством NULLS. Это плохая идея, с точки зрения хранения/восстановления/обслуживания, а также точки проверки данных (подробнее об этом позже).

Два наиболее распространенных соответствия:

1) Введите таблицу пользователя со всеми общими полями, включая поле "userType". Затем добавьте отдельную таблицу для каждого типа пользователя, содержащего дополнительные поля. Все пользователи имеют строку в таблице пользователей и одну или несколько таблиц конкретных типов пользователей. Это наиболее нормализованный и наиболее эффективный способ хранения и быстрого входа в систему. Это также позволяет использовать ограничения и внешние ключи, чтобы обеспечить доступность всей необходимой информации для каждого типа пользователя.

2) Создайте таблицу пользователя со всеми общими полями. Есть другая таблица, называемая как UserAttributes, у которой есть поля для идентификатора пользователя, ключа и значения. Любые дополнительные метаданные для конкретного пользователя могут быть сохранены здесь. Это имеет то преимущество, что не требуется, чтобы любое администрирование базы данных добавляло новые типы пользователей или метаданные, которые должны храниться для каждого типа пользователя. Тем не менее, он не позволяет выполнять проверку данных на уровне DB.

Ответ 2

Реляционная модель как таковая не поддерживает "наследование", что может помочь решить эту проблему (хотя некоторые механизмы БД, такие как PostgreSQL, поддерживают наследование).

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

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

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

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

Одна некоторая денормализация, которая может быть полезной здесь, - это столбец перечисления в таблице пользователей, указывающий "основную" или "единственную" роль каждого конкретного использования (он может быть нулевым и, возможно, равнозначным нулем в начале, если бы я был достаточно наглый, чтобы иметь его с самого начала...; -)... но я, скорее всего, буду ждать, чтобы добавить его, если и когда производительность некоторых конкретных запросов потребовала его в качестве конкретной оптимизации, а не для разработки схемы таким образом из (обратите внимание, что это ключевая причина никогда не использовать SELECT * FROM в ваших запросах - если вы ALTER TABLE позже добавили столбец, то SELECT * - это один бит, который сломался!).

Ответ 3

Это известный вопрос о нормализации.

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

Нормализовать или не нормализовать

Ответ 4

Вы не сказали, используете ли вы язык высокого уровня, поэтому я просто приведу общий пример с примером, похожим на DB:

Дизайн базы данных сложный. Итак, это будет быстрый и простой ответ.

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

Итак, пользователи - это ваша таблица. Он должен содержать основные, общие элементы (столбцы) данных, связанных с пользователем.

Затем этот другой набор информации (например, разрешения или что-то еще) - это другая таблица.

Просто убедитесь, что эта другая таблица имеет значение (столбец), которое указывает на пользователя, к которому оно относится. Вероятно, вы захотите сообщить своей базе данных о создании "индекса" между ними (чтобы улучшить производительность поиска и т.д.).

Например, "Таблица разрешений" для пользователей:

  - integer "id"        <--- unique, index column, auto-increment
  - integer "user_id"   <--- this is which user this belongs
  - ...
  - Boolean "can_write"         <--- example data column
  - Boolean "can_read"          <--- example data column
  - Boolean "can_reboot_system" <--- example data column
  - etc, whatever you want

Итак, вы можете "SELECT * FROM user_table WHERE first_name =" joe "(или такой)..., чтобы получить пользователя. Там я надеюсь, что у вас есть какое-то значение" id ", чтобы определить эту строку.

Теперь просто сделайте "SELECT * FROM разрешения WHERE user_id =" nnnn "(независимо от того, какой идентификатор пользователя).

Если пользователь имеет только 1 набор разрешений, то вы можете просто иметь этот user_id без дополнительного столбца "id".