Использование столбца порядка сортировки в таблице базы данных
Скажем, у меня есть таблица Product
в базе данных торгового сайта, чтобы хранить описание, цену и т.д. продуктов магазина. Каков наиболее эффективный способ сделать мой клиент в состоянии переупорядочить эти продукты?
Я создаю столбец Order
(целое число) для использования для сортировки записей, но это дает мне некоторые головные боли относительно производительности из-за примитивных методов, которые я использую, чтобы изменить порядок каждой записи после того, который мне действительно нужно изменить. Пример:
Id Order
5 3
8 1
26 2
32 5
120 4
Теперь, что я могу сделать, чтобы изменить порядок записи с ID=26
на 3?
Я создал процедуру, которая проверяет, есть ли запись в целевом порядке (3) и обновляет порядок строки (ID = 26), если нет. Если есть запись в целевом порядке, процедура выполняет сама посылка этого идентификатора строки с помощью target order + 1
в качестве параметров.
Это приводит к обновлению каждой отдельной записи после той, которую я хочу изменить, чтобы освободить место:
Id Order
5 4
8 1
26 3
32 6
120 5
Итак, что мог бы сделать более умный человек?
- Я использую SQL Server 2008 R2.
Edit:
Мне нужно, чтобы столбец заказа элемента был достаточным для сортировки без участия вторичных ключей. Только столбец заказа должен указать уникальное место для своей записи.
В дополнение ко всему, интересно, могу ли я реализовать что-то вроде связанного списка: столбец "Следующий" вместо столбца "Заказ", чтобы сохранить следующий идентификатор элементов. Но я не знаю, как написать запрос, который извлекает записи с правильным порядком. Если кто-то имеет представление об этом подходе, пожалуйста, поделитесь.
Ответы
Ответ 1
Update product set order = order+1 where order >= @value changed
Хотя со временем вы получите больше и больше "пробелов" в своем заказе, но он все равно "сортирует"
Это добавит 1 к изменяемому значению и каждому значению после него в одном из операторов, но приведенный выше оператор остается в силе. большие и большие "пробелы" формируются в вашем порядке, возможно, доходя до точки превышения значения INT.
Альтернативное решение с учетом желания без пробелов:
Представьте процедуру для: UpdateSortOrder с параметрами @NewOrderVal, @IDToChange, @OriginalOrderVal
Двухэтапный процесс, зависящий, если новый/старый порядок перемещается вверх или вниз по сортировке.
If @NewOrderVal < @OriginalOrderVal --Moving down chain
--Create space for the movement; no point in changing the original
Update product set order = order+1
where order BETWEEN @NewOrderVal and @OriginalOrderVal-1;
end if
If @NewOrderVal > @OriginalOrderVal --Moving up chain
--Create space for the momvement; no point in changing the original
Update product set order = order-1
where order between @OriginalOrderVal+1 and @NewOrderVal
end if
--Finally update the one we moved to correct value
update product set order = @newOrderVal where [email protected];
Что касается лучшей практики; в большинстве сред, в которых я обычно, есть что-то, сгруппированное по категориям и отсортированное по алфавиту или основанное на "популярности в продаже", тем самым отрицая необходимость предоставления определенного пользователем вида.
Ответ 2
Используйте старый трюк, который использует программы BASIC (среди других мест): переместите числа в столбце порядка на 10 или другое удобное приращение. Затем вы можете вставить одну строку (на самом деле, до 9 строк, если повезет) между двумя существующими номерами (это 10 друг от друга). Или вы можете перемещать строки с 370 по 565, не меняя ни одного из строк с 570 вверх.
Ответ 3
Одним из решений, которые я использовал в прошлом, с некоторым успехом, является использование "веса" вместо "порядка". Вес, являющийся очевидным, более тяжелый элемент (то есть: чем ниже число) опускается на дно, светлее (выше числа) поднимается вверх.
В случае, если у меня есть несколько элементов с одинаковым весом, я предполагаю, что они имеют одинаковую важность, и я заказываю их в алфавитном порядке.
Это означает, что ваш SQL будет выглядеть примерно так:
ORDER BY 'weight', 'itemName'
надеюсь, что это поможет.
Ответ 4
В настоящее время я разрабатываю базу данных с древовидной структурой, которую нужно заказать. Я использую метод типа link-list, который будет заказываться на клиенте (а не в базе данных). Заказ можно также выполнить в базе данных с помощью рекурсивного запроса, но это не обязательно для этого проекта.
Я сделал этот документ, который описывает, как мы собираемся реализовать хранилище порядка сортировки, включая пример в postgresql. Пожалуйста, не стесняйтесь комментировать!
https://docs.google.com/document/d/14WuVyGk6ffYyrTzuypY38aIXZIs8H-HbA81st-syFFI/edit?usp=sharing
Ответ 5
Вот альтернативный подход, использующий общее табличное выражение (CTE).
Этот подход учитывает уникальный индекс в столбце SortOrder и закрывает любые пробелы в последовательности порядка сортировки, которые могли быть оставлены после более ранних операций DELETE.
/* For example, move Product with id = 26 into position 3 */
DECLARE @id int = 26
DECLARE @sortOrder int = 3
;WITH Sorted AS (
SELECT Id,
ROW_NUMBER() OVER (ORDER BY SortOrder) AS RowNumber
FROM Product
WHERE Id <> @id
)
UPDATE p
SET p.SortOrder =
(CASE
WHEN p.Id = @id THEN @sortOrder
WHEN s.RowNumber >= @sortOrder THEN s.RowNumber + 1
ELSE s.RowNumber
END)
FROM Product p
LEFT JOIN Sorted s ON p.Id = s.Id
Ответ 6
Это очень просто. У вас должна быть "дыра в мощности".
Структура: вам нужно иметь 2 столбца:
pk = 32 бита int
order = 64bit bigint (БОЛЬШОЙ, НЕ ДВОЙНОЙ !!!)
Вставка /UpdateL
Когда вы вставляете первую новую запись, вы должны установить order = round(max_bigint / 2)
.
Если вы вставляете в начало таблицы, вы должны установить order = round("order of first record" / 2)
Если вы вставляете в конец таблицы, вы должны установить order = round("max_bigint - order of last record" / 2)
Если вы вставляете в середину, вы должны установить order = round("order of record before - order of record after" / 2)
Этот метод имеет очень большую мощность. Если у вас есть ошибка ограничения или вы думаете, что у вас небольшая мощность, вы можете перестроить столбец порядка (нормализовать).
В ситуации максимальности с нормализацией (с этой структурой) вы можете иметь "дыру в кардинальности" в 32 битах.
Это очень просто и быстро!
Помните, что нет двойного! Только INT - порядок является точным значением!