SQL для перемещения строк вверх или вниз в виде двух таблиц - PullRequest
2 голосов
/ 12 ноября 2011

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

1. [dbo.test_db_002] with columns:
[id] = INT NOT NULL IDENTITY(1,1) PRIMARY KEY
[name] = NVARCHAR(255)

и

2. [dbo.test_db_003] with columns:
[ord] = INT
[itmid] = INT NOT NULL PRIMARY KEY

В столбце [itmid] есть ограничение, связывающее его с [dbo.test_db_002]. [Id] примерно так:

ALTER TABLE [dbo.test_db_003] 
ADD CONSTRAINT fk1 FOREIGN KEY ([itmid]) 
REFERENCES [dbo.test_db_002]([id]) 
ON DELETE CASCADE ON UPDATE CASCADE;

Скажем, таблица [dbo.test_db_002] содержит следующие данные:

[id] [name] 
3    John
5    Mary
8    Michael
10   Steve
13   Jack
20   Pete

и [dbo.test_db_003] имеют следующие данные для заказа:

[ord] [itmid]
1      5
4      8
5      13
8      3
10     10
13     20

Поэтому, когда я получаю имена из базы данных, я использую следующий SQL:

SELECT [name]
FROM   [dbo.test_db_002] t1
LEFT JOIN [dbo.test_db_003] t2 ON t1.[id]=t2.[itmid]
ORDER BY t2.[ord] ASC

Создает список имен (упорядоченный по столбцу [dbo.test_db_003]. [Ord]):

Mary
Michael
Jack
John
Steve
Pete

То, что я ищу, - это возможность перемещать каждое из имен вверх и вниз по списку. Например, если я хочу переместить «Джона» на одну позицию вверх, что мне делать?

До сих пор я придумал этот частичный SQL:

WITH cte AS
(
    SELECT [id], [ord], ROW_NUMBER() OVER (ORDER BY t2.[ord] ASC) AS rowNum
    FROM [dbo.test_db_002] t1
    LEFT JOIN [dbo.test_db_003] t2 ON t1.[id] = t2.[itmid]
)

Это выберет следующее:

rowNum  [id]  [ord]
1        1     5
2        4     8
3        5     13
4        8     3
5        10    10
6        13    20

Итак, я понимаю, что мне нужно сдвинуть значения в столбце [ord] на единицу, начиная с индекса 3 (поскольку индекс "John" равен 4), а затем каким-то образом установить для [ord] для "John" значение 5, но как ты это делаешь?

1 Ответ

2 голосов
/ 12 ноября 2011

Я подготовил полную демонстрацию для вас, как это может работать на data.stackexchange.com.
Решение с учетом вашего комментария:

движение вверхили вниз может быть только один шаг - другими словами, нельзя перемещать 2 или более позиций

В примере я делаю Джону ординарные позиции с Джеком над ним:

WITH x AS (
  SELECT t2.itmid, t2.ord
  FROM   dbo.test_db_002 t1
  LEFT   JOIN dbo.test_db_003 t2 ON (t1.id = t2.itmid)
  WHERE  t1.name = 'John'  -- must be unique, or query by id ...
  )
  , y AS (
  SELECT TOP 1
         t.itmid, t.ord
  FROM   dbo.test_db_003 t, x
  WHERE  t.ord < x.ord     -- smaller ord = "above"
  ORDER  BY t.ord DESC
  )
UPDATE dbo.test_db_003 SET ord = z.ord
FROM (
   SELECT x.itmid, y.ord FROM x,y
   UNION ALL
   SELECT y.itmid, x.ord FROM x,y
   ) z
WHERE  dbo.test_db_003.itmid = z.itmid   

Основные моменты:

  1. Использование двух CTE для структурирования запроса:
  2. Получить идентификатор и порядковый номер Джона
  3. Получить то же самое для человека над ним
  4. Подготовьте две строки, где эти два порядковых номера переключаются с помощью UNION ALL
  5. Используйте эти две строки в простом UPDATE

    • порядковая позиция ord должна разрешать передачу дубликатов, чтобы это работало.
    • Если никого нет "выше", запрос ничего не делает.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...