Заполните последовательность в строках sql - PullRequest
0 голосов
/ 01 февраля 2011

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

Например, если у меня изначально есть такой набор значений:

+----+--------+-----+
| id | name   | pos |
+----+--------+-----+
|  1 | one    |   1 |
|  2 | two    |   2 |
|  3 | three  |   3 |
|  4 | four   |   4 |
+----+--------+-----+

И вторая строка была удалена, позиция всех последующих строк должна быть обновлена, чтобы закрыть пропуски. Результат должен быть таким:

+----+--------+-----+
| id | name   | pos |
+----+--------+-----+
|  1 | one    |   1 |
|  3 | three  |   2 |
|  4 | four   |   3 |
+----+--------+-----+

Есть ли способ сделать это обновление в одном запросе? Как я мог это сделать?

PS: Я был бы признателен за примеры как для SQLServer, так и для Oracle, поскольку система должна поддерживать оба механизма. Спасибо!

ОБНОВЛЕНИЕ: Причина этого заключается в том, что пользователям разрешено изменять позиции по желанию, а также добавлять или удалять новые строки. Позиции показываются пользователю, и по этой причине они должны постоянно отображать последовательность (и эта последовательность должна быть сохранена, а не сгенерирована по требованию).

Ответы [ 3 ]

4 голосов
/ 01 февраля 2011

Не уверен, что это работает, но с Oracle я бы попробовал следующее:

update my_table set pos = rownum;
0 голосов
/ 01 февраля 2011

Вам действительно нужно, чтобы значения последовательности были смежными, или вам просто нужно иметь возможность отображать смежные значения? Самый простой способ сделать это состоит в том, чтобы позволить фактической последовательности стать разреженной и вычислить ранг на основе порядка:

select id, 
       name, 
       dense_rank() over (order by pos) as pos,
       pos as sparse_pos 
from my_table

(примечание: это специфичный для Oracle запрос)

Если вы сделаете позицию разреженной в первую очередь, это даже упростит повторный порядок, поскольку вы можете сделать каждую новую позицию на полпути между двумя существующими. Например, если у вас была такая таблица:

+----+--------+-----+
| id | name   | pos |
+----+--------+-----+
|  1 | one    | 100 |
|  2 | two    | 200 |
|  3 | three  | 300 |
|  4 | four   | 400 |
+----+--------+-----+

Когда придет время переместить ID 4 в положение 2, вы просто измените положение на 150.


Дальнейшее объяснение:

Используя приведенный выше пример, пользователь изначально видит следующее (потому что вы маскируете позицию):

+----+--------+-----+
| id | name   | pos |
+----+--------+-----+
|  1 | one    |   1 |
|  2 | two    |   2 |
|  3 | three  |   3 |
|  4 | four   |   4 |
+----+--------+-----+

Когда пользователь через ваш интерфейс указывает, что запись в позиции 4 должна быть перемещена в позицию 2, вы обновите позицию с идентификатором 4 до 150, а затем повторно выполните свой запрос. Пользователь видит это:

+----+--------+-----+
| id | name   | pos |
+----+--------+-----+
|  1 | one    |   1 |
|  4 | four   |   2 |
|  2 | two    |   3 |
|  3 | three  |   4 |
+----+--------+-----+

Единственная причина, по которой это не сработает, заключается в том, что пользователь редактирует данные непосредственно в базе данных. Хотя даже в этом случае я был бы склонен использовать такое решение с помощью представлений и вместо триггеров.

0 голосов
/ 01 февраля 2011

это будет работать, но может быть неоптимальным для больших наборов данных:

SQL> UPDATE my_table t
  2     SET pos = (SELECT COUNT(*) FROM my_table WHERE id <= t.id);

3 rows updated

SQL> select * from my_table;

        ID NAME              POS
---------- ---------- ----------
         1 one                 1
         3 three               2
         4 four                3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...