Как представлять и вставлять в упорядоченный список в SQL?
Я хочу представлять список "привет" , "привет" , "до свидания" , "хороший день", "howdy" (с этим порядком) в таблице SQL:
pk | i | val
------------
1 | 0 | hi
0 | 2 | hello
2 | 3 | goodbye
3 | 4 | good day
5 | 6 | howdy
'pk' является столбцом первичного ключа. Не обращайте внимания на его значения.
'i' - это "индекс", который определяет этот порядок значений в столбце "val". Он используется только для установления порядка, и значения в противном случае несущественны.
Проблема, с которой я столкнулась, заключается в введении значений в список при сохранении порядка. Например, если я хочу вставить "эй", и я хочу, чтобы он появился между "привет" и "до свидания" , тогда мне нужно переместить значения "i" "до свидания" и "хороший день" (но предпочтительно не "howdy" ), чтобы освободить место для новой записи.
Итак, существует ли стандартный шаблон SQL для операции сдвига, но только сдвиг необходимых элементов? (Заметим, что простая "таблица UPDATE SET я = я + 1 WHERE я >= 3" не работает, поскольку она нарушает ограничение уникальности на "i", а также без необходимости обновляет строку "howdy".)
Или, есть ли лучший способ представить упорядоченный список? Я предполагаю, что вы можете сделать "i" значение с плавающей запятой и выбрать значения между ними, но тогда вы должны иметь отдельную операцию перебалансировки, если такое значение не существует.
Или существует ли какой-то стандартный алгоритм для создания строковых значений между произвольными другими строками, если я должен был сделать "i" varchar?
Или я должен просто представлять его как связанный список? Я избегал этого, потому что я хотел бы также сделать SELECT.. ORDER BY, чтобы получить все элементы в порядке.
Ответы
Ответ 1
Вы можете легко достичь этого, используя каскадный триггер, который обновляет любую запись "индекса", равную новой в операции вставки/обновления, до значения индекса +1. Это будет каскадом через все строки, пока первый зазор не остановит каскад - см. Второй пример в этой записи в блоге для реализации PostgreSQL.
Этот подход должен работать независимо от используемой РСУБД, при условии, что он предлагает поддержку запуска триггеров перед обновлением/вставкой. Это в основном делает то, что вы сделали бы, если бы вы реализовали свое желаемое поведение в коде (увеличьте все последующие значения индекса до тех пор, пока не получите разрыв), но более простым и эффективным способом.
В качестве альтернативы, если вы можете жить с ограничением на SQL Server, проверьте тип иерархии. Хотя в основном они предназначены для определения вложенных иерархий, вы можете использовать его и для плоского упорядочения. Он несколько напоминает ваш подход с использованием float, поскольку он позволяет вставлять между двумя позициями путем назначения дробных значений, тем самым избегая необходимости обновлять другие записи.
Ответ 2
Как я читал ваше сообщение, я продолжал думать "связанный список",
и в конце я все еще думаю, что путь.
Если вы используете Oracle, а связанный список - это отдельная таблица (или даже та же таблица с идентификатором самореализации), которую я бы избегал), вы можете использовать запрос CONNECT BY и псевдо-столбковый уровень для определения порядок сортировки.
Ответ 3
Если вы не используете числа, но Strings, у вас может быть таблица:
pk | i | val
------------
1 | a0 | hi
0 | a2 | hello
2 | a3 | goodbye
3 | b | good day
5 | b1 | howdy
Вы можете вставить a4 между a3 и b, a21 между a2 и a3, a1 между a0 и a2 и так далее. Вам понадобится умная функция, чтобы генерировать я для нового значения v между p и n, и индекс может стать длиннее и длиннее, или время от времени требуется большая перебалансировка.
Другой подход может заключаться в том, чтобы реализовать (двойной) связанный список в таблице, где вы не сохраняете индексы, а ссылки на предыдущие и последующие, что означает, что вы обычно должны обновлять 1-2 элементов:
pk | prev | val
------------
1 | 0 | hi
0 | 1 | hello
2 | 0 | goodbye
3 | 2 | good day
5 | 3 | howdy
эй между привет и до свидания:
hey get pk 6,
pk | prev | val
------------
1 | 0 | hi
0 | 1 | hello
6 | 0 | hi <- ins
2 | 6 | goodbye <- upd
3 | 2 | good day
5 | 3 | howdy
предыдущий элемент был бы hello
с pk = 0, а goodbye
, связанный с hello
, теперь должен ссылаться на hey
в будущем.
Но я не знаю, если можно найти механизм "порядок" для многих db-реализаций.
Ответ 4
Я попытался ответить на аналогичный вопрос на этот пост: Переупорядочить упорядоченный список. Надеюсь, это поможет.