SQL以两表排列方式向上或向下移动行

时间:2011-11-12 07:24:55

标签: sql sql-server tsql

我有两个表,我这样设计可能会重新考虑元素:

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

我正在寻找的是在列表中上下移动每个名称的选项。例如,如果我想将“John”移动一个位置,我该怎么办?

到目前为止,我想出了这个部分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)然后以某种方式将“John”的[ord]设置为5,但你是怎么做到的?

1 个答案:

答案 0 :(得分:2)

我为你准备了一个complete demo如何在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. 得到约翰的身份&amp;序数位置
  3. 为他上面的人取得同样的成就
  4. UNION ALL
  5. 的帮助下准备这两个切换序号的两行
  6. 在现在简单的UPDATE

    中使用这两行
    • 序号位置ord必须允许传递重复项才能生效。
    • 如果上面没有人,则查询将默默无效。