Общей потребностью при использовании базы данных является доступ к записям по порядку. Например, если у меня есть блог, я хочу изменить порядок своих сообщений в блоге в произвольном порядке. Эти записи часто имеют много связей, поэтому реляционная база данных, кажется, имеет смысл.
Общее решение, которое я видел, состоит в том, чтобы добавить целочисленный столбец order
:
CREATE TABLE AS your_table (id, title, sort_order)
AS VALUES
(0, 'Lorem ipsum', 3),
(1, 'Dolor sit', 2),
(2, 'Amet, consect', 0),
(3, 'Elit fusce', 1);
Затем мы можем отсортировать строки, order
чтобы получить их в правильном порядке.
Однако это кажется неуклюжим
- Если я хочу переместить запись 0 в начало, я должен изменить порядок каждой записи
- Если я хочу вставить новую запись в середине, я должен изменить порядок каждой записи после нее
- Если я хочу удалить запись, я должен изменить порядок каждой записи после нее
Легко представить такие ситуации, как:
- Две записи имеют одинаковые
order
order
Между записями есть пробелы
Это может произойти довольно легко по ряду причин.
Такой подход используют такие приложения, как Joomla:
Вы можете утверждать, что интерфейс здесь плохой, и что вместо того, чтобы люди непосредственно редактировали числа, им следует использовать стрелки или перетаскивание - и вы, вероятно, были бы правы. Но за кулисами происходит то же самое.
Некоторые люди предлагают использовать десятичную для сохранения порядка, так что вы можете использовать «2.5» для вставки записи между записями в порядке 2 и 3. И хотя это немного помогает, возможно, это даже более грязно, потому что вы можете в конечном итоге с странные десятичные дроби (где вы остановитесь? 2,75? 2,875? 2,8125?)
Есть ли лучший способ хранить заказ в таблице?
источник
orders
и ddl.Ответы:
Нет, есть более простой способ.
Это правда, если только вы не используете тип данных, который поддерживает значения «между». Числа с плавающей точкой и числовые типы позволяют обновить значение, скажем, до 2,5. Но varchar (n) тоже работает. (Думайте 'a', 'b', 'c'; затем думайте 'ba', 'bb', 'bc'.)
Нет, есть более простой способ. Просто удалите строку. Остальные строки все равно будут отсортированы правильно.
Уникальное ограничение может предотвратить это.
Пробелы не влияют на то, как dbms сортирует значения в столбце.
Вы не остановитесь, пока не должны . У DBM нет проблем с сортировкой значений, которые имеют 2, 7 или 15 знаков после запятой.
Я думаю, что ваша настоящая проблема в том, что вы хотели бы видеть значения в отсортированном порядке как целые числа. Вы можете сделать это.
источник
with cte as (select *,row_number() over (order by sort_order desc) as row from test) update cte set sort_order=row;
Это очень просто. Вы должны иметь структуру "кардинальной дыры":
Вам нужно иметь 2 столбца:
integer
bigint
( неdouble
)Вставка / обновление
order = round(max_bigint / 2)
.order = round("order of first record" / 2)
order = round("max_bigint - order of last record" / 2)
4) При вставке в середине установитеorder = round("order of record before - order of record after" / 2)
Этот метод имеет очень большую мощность. Если у вас есть ошибка ограничения или если вы думаете, что у вас небольшая мощность, вы можете перестроить столбец порядка (нормализовать).
В максимальной ситуации с нормализацией (с этой структурой) вы можете иметь «дыру в кардинальности» в 32 битах.
Помните, что не следует использовать типы с плавающей точкой - порядок должен быть точным значением!
источник
Как правило, упорядочение производится в соответствии с некоторой информацией в записях, заголовком, идентификатором или чем-либо, что подходит для данной конкретной ситуации.
Если вам нужен специальный порядок, использование целочисленного столбца не так плохо, как может показаться. Например, чтобы освободить место для записи на 5-м месте, вы можете сделать что-то вроде:
update table_1 set place = place + 1 where place > 5
,Надеюсь, вы можете объявить столбец
unique
и, возможно, иметь процедуру, чтобы сделать перестановки «атомарными». Детали зависят от системы, но это общая идея.источник
Какая разница? Эти цифры предназначены только для компьютера, поэтому не имеет значения, сколько у них дробных цифр или насколько они уродливы.
Использование десятичных значений означает, что для перемещения элемента F между элементами J и K все, что вам нужно сделать, это выбрать значения порядка для J и K, затем усреднить их, а затем обновить F. Два оператора SELECT и один оператор UPDATE (вероятно, это делается с использованием сериализуемой изоляции, чтобы избежать тупики).
Если вы хотите видеть целые числа, а не дроби в выходных данных, то либо рассчитайте целые числа в клиентском приложении, либо используйте функции ROW_NUMBER () или RANK () (если ваша СУБД включает их).
источник
В моем собственном проекте я планирую попробовать решение, подобное решению с десятичным числом, но вместо этого использовать байтовые массивы:
Идея состоит в том, что вы никогда не можете исчерпать возможные промежуточные значения, потому что вы просто добавляете a
b"\x00"
к соответствующим записям, если вам нужно больше значений. (int
не ограничен в Python 3, в противном случае вам придется выбирать срез байтов в конце для сравнения, при условии, что между двумя смежными значениями различия будут упакованы ближе к концу.)Например, скажем, у вас есть две записи,
b"\x00"
иb"\x01"
, и вы хотите, чтобы запись проходила между ними. Там нет никаких доступных значений между0x00
и0x01
, таким образом вы добавитеb"\x00"
к обеим, и теперь у вас есть несколько значений между ними вы можете использовать для вставки новых значений.База данных может легко сортировать это, потому что все заканчивается в лексикографическом порядке. Если вы удалите запись, она все еще в порядке. В моем проекте я сделал
b"\x00"
иb"\xff"
какFIRST
иLAST
записи, однако, чтобы использовать их как виртуальные значения «от» и «до» для добавления / добавления новых записей:источник
Я нашел этот ответ намного лучше. Цитирую это целиком:
источник