#database #database-design #relational-database
#База данных #база данных-дизайн #реляционная база данных
Вопрос:
Я создаю базу данных для веб-приложения, в котором пользователи могут отправлять данные. Каждая база данных уникальна, и более одного пользователя могут отправлять одну и ту же базу данных.
С точки зрения приложения важно знать порядок, в котором пользователи отправляли данные.
Я создал таблицу исключительно для этой цели. Он содержит следующие поля:
SubmissionID
UserID
SubmissionOrder
... # and other non-important ones
Мой вопрос в том, какие атрибуты я должен сделать первичными ключами?
SubmissionID
и UserID
допускал бы дублирование SubmissionOrder
s для (SubmissionID, UserID)
пары.
SubmissionID
и SubmissionOrder
позволит одному и тому же пользователю отправлять одно и то же дважды.
UserID
и SubmissionOrder
… значительно ограничило бы пользователя с точки зрения того, что он может отправить :P
Все три допускают дублирование SubmissionOrder
s для разных UserID
s.
Есть ли другое решение, о котором я не размышляю?
Лучше ли решать эту проблему на уровне приложения? С триггерами?
Спасибо за ваше время!
PS: Некоторые технические детали, которые, я сомневаюсь, вы найдете полезными:
- Приложение написано на PHP
- База данных работает на sqlite3
Комментарии:
1. Я думаю, вы сделали вопрос слишком расплывчатым, возможно, пытаясь не указывать детали домена. Сложно смоделировать что-то настолько расплывчатое (есть данные, и они мне нужны по порядку, и эти столбцы, которые не определены как полезные, похоже, не делают этого для меня).
2. @MarkBrackett — Прошу прощения. Что еще вам нужно знать об этом? Пользователь отправляет часть данных. Другой пользователь отправляет ту же часть данных. Мне нужно знать порядок, в котором пользователи отправили указанную часть данных.
Ответ №1:
Порядок, в котором все происходит, просто немного нечеткий на большинстве платформ SQL. Насколько я знаю, ни одна платформа SQL не гарантирует оба этих требования.
- Связей быть не должно.
- Более ранние отправки всегда должны выглядеть так, как будто они были раньше, чем более поздние отправки.
В столбце с меткой времени более ранние отправки всегда выглядят так, как будто они были раньше, чем более поздние отправки. Но легко возможно иметь две «отправки» с одинаковым значением временной метки, независимо от того, насколько хорошо разрешение временной метки вашей СУБД.
С серийным номером (или номером автоматического добавления) связей не будет. Но платформы SQL не гарантируют, что строка с порядковым номером 2 будет зафиксирована перед строкой с порядковым номером 3. Это означает, что если вы записываете как серийный номер, так и временную метку, вы можете найти пары строк, в которых строка с меньшим серийным номером также имеет более позднюю временную метку.
Но SQLite — это не совсем SQL, поэтому он может быть исключением из этого общего правила.
В SQLite любой процесс, который выполняет запись в базу данных, блокирует всю базу данных. Я думаю, что блокировка базы данных означает, что вы можете полагаться на то, что rowid() будет временно увеличиваться.
Итак, я думаю, что вы смотрите на первичный ключ {SubmissionID, userId} , где rowid() определяет порядок отправки. Но я могу ошибаться.
Ответ №2:
Что касается вашего конкретного вопроса :
С точки зрения приложения важно знать порядок, в котором пользователи отправляли данные
Я думаю, что есть 2 альтернативных варианта, чем объединенный первичный ключ поля:
(1) Создайте дополнительный столбец — один целочисленный (автоинкрементный) первичный ключ.
или
(2) Создайте поле метки времени и сохраните дату / время ввода данных.
Комментарии:
1. Я использую второй вариант — он меня вполне устраивает.
Ответ №3:
Итак, у вас есть отправленные данные (SubmissionId?), Для которых вы хотите разрешить дубликаты (чтобы другой пользователь мог отправлять дубликаты данных), но не дубликаты для одного пользователя. Это требует уникального ограничения на (SubmissionId, userId).
Ваше следующее требование заключается в том, чтобы вы «знали порядок, в котором пользователи отправляли данные». Неясно, верно ли это для всех отправлений или только для отправлений, которые имеют дубликаты *. Решение общего случая (все отправки) решает конкретную проблему, поэтому мы пойдем с этим.
Поскольку это проблема упорядочения, с которой SQL на самом деле не справляется, вам нужно добавить атрибут, который даст вам абсолютный порядок. 2 стандартных варианта — это автоинкремент или временная метка. Мы выберем автоинкремент, чтобы вам не приходилось беспокоиться о связях. Я предполагаю, что SubmissionOrder является вашим заполнителем для этого. Поскольку мы использовали столбец с автоинкрементом, он гарантированно будет уникальным. Итак, у нас есть еще одно уникальное ограничение на (SubmissionOrder) .
Теперь эти уникальные ограничения являются вашими ключами-кандидатами. Выберите один в качестве первичного ключа и используйте уникальное ограничение для другого.
*
Ваши комментарии о повторяющемся порядке отправки немного запутывают проблему — предполагая, что SubmissionOrder уникален только для SubmissionId. Предполагая, что у вас есть логика приложения для создания следующего порядка отправки, это допустимая (хотя и немного более сложная) альтернатива. В этом случае ваше уникальное ограничение будет включено (SubmissionId, SubmissionOrder).