我的任务是创建自定义存储过程:
exec UPDATE_PROJECT_ORDER @PROJECTID=12, @UPDATEMODE=0
这将在表中的一行更新后执行。
不幸的是,我真的很难过(以至于我什至不确定这是否可能)我一直在努力简化我正在做的事情,并想知道我是否可以就代码本身向董事会寻求帮助......
因此,存储过程/代码的目的是通常按顺序对项目列表重新排序,重新排序会根据传入的参数更改,该参数将保留表中设置的值用户并围绕它对列表的其余部分进行排序,或者将其重新编号为序列中的下一个数字。我认为我们可以假设 UPDATEMODE=0 大部分时间都是默认的。
我有一个看起来像这样的表:
---------------------------------------
| ID | POSITION | OLD_POS |
---------------------------------------
| 10 | 1 | |
| 11 | 2 | |
| 12 | 3 | |
| 13 | 4 | |
---------------------------------------
如果用户决定给 ID 为 12 的记录(ID 与存储过程一起传入)更高的优先级,例如 1,那么应该发生的是其他记录(10 / 11 / 13)应该按顺序重新围绕它排序(2 / 3 / 4),这将影响它们在前端的显示方式,例如
---------------------------------------
| ID | POSITION | OLD_POS |
---------------------------------------
| 10 | 2 | 1 |
| 11 | 3 | 2 |
| 12 | 1 | 3 |
| 13 | 4 | 4 |
---------------------------------------
另一个示例是记录 ID 12 的位置从 1 更改为 7,因此该数据集:
---------------------------------------
| ID | POSITION | OLD_POS |
---------------------------------------
| 10 | 2 | 1 |
| 11 | 3 | 2 |
| 12 | 1/7 | 3 |
| 13 | 4 | 4 |
---------------------------------------
位置数据重新排序为:
---------------------------------------
| ID | POSITION | OLD_POS |
---------------------------------------
| 10 | 1 | 2 |
| 11 | 2 | 3 |
| 12 | 7 | 1 |
| 13 | 3 | 4 |
---------------------------------------
如上所述 - 在存储过程中,需要传入另一个参数(@UPDATEMODE,可以是 0 或 1),这会改变函数的行为,允许用户指定他们想要的位置并重新排序列出它而不是使其成为序列中的下一个数字,例如,它们将第 3 行中的优先级从值 1 更新为值 7
此数据集第 12 行位置值 = 1,但更改为 7,其中 UPDATEMODE 指定为 1:
---------------------------------------
| ID | POSITION | OLD_POS |
---------------------------------------
| 10 | 2 | 1 |
| 11 | 3 | 2 |
| 12 | 1/7 | 3 |
| 13 | 4 | 4 |
---------------------------------------
这将重新排序列表如下:
---------------------------------------
| ID | POSITION | OLD_POS |
---------------------------------------
| 10 | 1 | 2 |
| 11 | 2 | 3 |
| 12 | 4 | 1 |
| 13 | 3 | 4 |
---------------------------------------
在此示例中,存储过程将被称为:
exec UPDATE_PROJECT_ORDER @PROJECTID=12, @UPDATEMODE=1
这是我一直在使用的 SQL 代码:
-- Declare variables
DECLARE @PROJECTID INTEGER
DECLARE @CURRENTPOSITION INTEGER
DECLARE @ROLLBACKPOSITION INTEGER
DECLARE @STARTPOSITION INTEGER
DECLARE @ENDPOSITION INTEGER
-- For testing hardcode a REQUEST ID
SET @PROJECTID = 12
-- Start Position value
SET @STARTPOSITION = 1
-- End Position value
SELECT @ENDPOSITION = COUNT(ID) FROM PROJECT WHERE PROJECT_ORDER IS NOT NULL
-- Update Rollback column with current value
UPDATE PROJECT SET OLD_POS = POSITION WHERE POSITION IS NOT NULL
DECLARE cursorProjectPositionUpdate CURSOR fast_forward
FOR
SELECT ID, POSITION, OLD_POS
FROM PROJECT
WHERE ID = @PROJECTID
AND POSITION IS NOT NULL
OPEN cursorProjectPositionUpdate
FETCH NEXT FROM cursorProjectPositionUpdate INTO @PROJECTID, @CURRENTPOSITION, @ROLLBACKPOSITION
WHILE @@FETCH_STATUS = 0
BEGIN
WHILE (@STARTPOSITION <= @ENDPOSITION)
IF @STARTPOSITION = 1
UPDATE PROJECT
SET POSITION = @STARTPOSITION
WHERE ID = @PROJECTID
AND OLD_POSITION = @ROLLBACKPOSITION
ELSE
UPDATE PROJECT
SET POSITION = @STARTPOSITION
WHERE OLD_POS = @ROLLBACKPOSITION
AND ID <> @PROJECTID
SET @STARTPOSITION = @STARTPOSITION + 1
FETCH NEXT FROM cursorProjectPositionUpdate INTO @PROJECTID, @CURRENTPOSITION, @ROLLBACKPOSITION
END
CLOSE cursorProjectPositionUpdate
DEALLOCATE cursorProjectPositionUpdate
我使用了游标,因为最多可以重新排序 25 条记录的硬性限制,所以我不太担心性能。虽然表中可能有超过 25 条记录,这就是为什么我尝试使用 AND POSITION IS NOT NULL 子句排除记录的原因,所以我希望这是可以接受的。
我脑海中的想法是计算我总共有多少条记录有一个位置,然后循环将第一个设置为位置 1,然后将其余的设置为下一个顺序。
我发现的最大问题是记录的匹配,即我的 WHERE 子句,因为存储过程传入的唯一内容是我想要设置为位置 1 的 ID,所以我怎么知道接下来是哪个...逻辑是它应该是列表中的下一个最低 ID 号。
这是在 MS SQL Server 中完成的。
我试图避免创建任何临时表,因此需要查看是否可以一并完成。
希望这对某人有某种意义,我对解决方案持开放态度,并将尽可能多地分享信息。
非常感谢!
额外的
根据下面的答案,我一直在考虑这个问题,我再次试图让这个尽可能简单,所以我有存储过程,它传入了一个 PROJECT ID 值,所以如果我循环遍历所有我拥有的与我的项目 ID 不匹配的值将它们从 2 开始重置到我的终点,这是基于我拥有的记录数,一旦这些记录按顺序设置,将传入项目的位置设置为 1 . 我知道这不适合我的更新模式选项,但我担心这只会增加很多复杂性。
因此,就代码而言,您对以下内容有何想法:
-- Declare variables
DECLARE @PROJECTID INTEGER
DECLARE @STARTPOSITION INTEGER
DECLARE @ENDPOSITION INTEGER
-- Hardcoded for testing
SET @PROJECTID = 25061
-- Start Position value
SET @STARTPOSITION = 2
-- End Position value
SELECT @ENDPOSITION = COUNT(ID) FROM PROJECT WHERE PROJECT_ORDER IS NOT NULL AND ID <> @PROJECTID
-- Update Rollback column with current value
UPDATE PROJECT SET PROJECT_ORDER_RB = PROJECT_ORDER WHERE PROJECT_ORDER IS NOT NULL
-- Loop other records
WHILE (@STARTPOSITION <= @ENDPOSITION)
UPDATE PROJECT SET PROJECT_ORDER = @STARTPOSITION WHERE ID <> @PROJECTID
AND PROJECT_ORDER IS NOT NULL AND (PROJECT_ORDER = 1 OR PROJECT_ORDER => @STARTPOSITION OR PROJECT_ORDER <= @ENDPOSITION)
SET @STARTPOSITION = @STARTPOSITION + 1
-- Finally set passed in Project to Position 1
UPDATE PROJECT SET PROJECT_ORDER = 1 WHERE ID = @PROJECTID