Проектирование реляционной базы данных при работе с полем m2m - PullRequest
0 голосов
/ 06 декабря 2018

Допустим, у меня есть следующие таблицы:

User : id, login, password

Card : id, name, value

И User может иметь один и тот же Card несколько раз.Например: User с идентификатором 1 может иметь несколько Card с идентификатором 1.

Я бы создал следующую таблицу:

UserCard : id, user_id, card_id

ИтакНапример, UserCard может выглядеть следующим образом:

| id | user_id | card_id |
|1   | 1       | 1       |
|2   | 1       | 1       |
|3   | 1       | 2       |

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

| id | user_id | card_id | quantity |
|1   | 1       | 1       | 2        |
|2   | 1       | 2       | 1        |

было бы лучшим способом сделать это, потому что он удаляет дубликаты строк.

На мой взгляд, это неправильно по следующим причинам:

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

Моя коллега высказал такую ​​точку зрения:

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

Вопрос:

Каким будет лучший дизайн базы данных для этого случая?У пользователя может быть 0 или любые карты с одинаковым идентификатором

РЕДАКТИРОВАТЬ:

мы используем Django с postgrsql Нет коллег, мне просто интересно, какой будет лучший дизайн базы данных

Ответы [ 2 ]

0 голосов
/ 07 декабря 2018

Ваш коллега прав.Я дам вам краткий обзор теории и пример того, почему, но вам будет лучше, если вы прочитаете учебник CJ Date.

Основная проблема с таблицей UserCard состоит в том, что у нее нет естественного ключа .Вы добавили бессмысленное значение id, чтобы сделать его «уникальным», но нет никакого существенного различия между идентификаторами 1 и 2: нет 1006 * различий: в их значениях нет различий, поэтому то, что они представляют, неразличимо.Когда вы обнаруживаете, что отслеживаете вещи, которые не можете отличить друг от друга, обычным решением является их подсчет.Это то, что ваш банк делает с долларами.

Реляционная теория основана на наборах различных (неповторяющихся) элементов.Вы игнорируете это основание на свой страх и риск.

На практике - и только один пример - что происходит, когда пользователь сбрасывает одну карту?Как вы удалите неразличимую строку?Ваш коллега может сказать:

update UserCard set quantity = quantity - 1 where user = 1 and card = 1
delete UserCard where quantity = 0

Что вы будете делать?Обойти проблему с другим не теоретическим клуджем, таким как limit 1?Что если ограничение не равно 1, потому что произвольная группа пользователей сбросила свои карты?

Вы частично помогли себе с помощью своей искусственной уникальности:

delete UserCard where id = 
       (select min(id) from UserCard where user = 1 and card = 1)

, которая показывает, насколько уникальна полезна.Но quantity твой друг.Следовательно, ваш дизайн и запрос будут проще, если вы будете использовать теорию вместо борьбы с ней.

0 голосов
/ 06 декабря 2018

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

create table #user
(
    id int identity(1,1),
    login nvarchar(100),
    password nvarchar(100)
)
create table #card
(
    id int identity(1,1),
    name nvarchar(100),
    value int
)
create table #usercard
(
    id int identity(1,1),
    user_id int, /* <-- (in theory) foreign key to #user table*/
    card_id int /* <-- (in theory) foreign key to #card table */
)
insert into #user (login, password) values
('user1','password1'),
('user2','password2')

insert into #card (name, value) values
('card1', 1),
('card2', 2),
('card3', 3)

insert into #usercard (user_id, card_id) values
(1,1),
(1,2),
(2,3)

select a.id as user_id, count(b.card_id) as quantity from #user a
inner join #usercard b on a.id = b.user_id
inner join #card c on b.card_id = c.id
group by a.id

При проектировании базы данных 3-я таблица (#usercard) называется «Junction Table».И этот дизайн предпочтителен, когда вы хотите добиться нормализации базы данных.

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