【问题标题】:Stored procedure To Delete rows then renumber column存储过程删除行然后重新编号列
【发布时间】:2013-12-12 17:17:11
【问题描述】:

我需要一个从TBL_1 中删除行的过程,其中TASK_ID 介于@FirstID@LastIDPROJECT_ID = @PROJECT_ID 之间

然后将TASK_ID 重新编号为顺序(这就是问题所在)

task_ID 必须是连续的,这样我正在使用的网格才能正常工作。

表结构是

ID (int PK), TASK_ID (INT), project_id (INT), other columns 

我完全不知道如何使用存储过程来做到这一点。我在前端应用程序中有一个方法可以处理这个问题,但我知道 SP 会更好,我不知道如何解决这个问题。任何帮助将不胜感激。

【问题讨论】:

  • Task_Id 的顺序如何
  • 顺序基于什么?如果您可以确定在运行更新的查询中,为什么还要存储它呢?只需在查询时生成序列号,就不必不断运行以保持最新。
  • 换句话说,你可能还不熟悉ROW_NUMBER()
  • 没错,我不熟悉row_number。
  • task_id 列是连续的 1,2,3,4,5.... 如果我删除 2-4,那么剩余的第 5 行现在必须是 2,而第 6 行现在应该是 3

标签: stored-procedures sql-server-2008-r2


【解决方案1】:

鉴于此示例数据:

USE tempdb;
GO

CREATE TABLE dbo.TBL_1
(
  Project_ID INT,
  Task_ID INT,
  Description VARCHAR(32),
  PRIMARY KEY (Project_ID, Task_ID)
);

INSERT dbo.TBL_1(Project_ID, Task_ID, Description)
VALUES(1,1,'Task 1'),(1,2,'Task 2'),(1,3,'Task 3'),
      (1,4,'Task 4'),(1,5,'Task 5'),(1,6,'Task 6');

GO

创建存储过程:

CREATE PROCEDURE dbo.RenumberTasksWithRedundantInformation
  @Project_ID INT,
  @FirstTaskID INT,
  @LastTaskID INT
AS
BEGIN
  SET NOCOUNT ON;

  BEGIN TRANSACTION;

  DELETE dbo.TBL_1 
    WHERE Project_ID = @Project_ID 
      AND Task_ID BETWEEN @FirstID AND @LastID;

  ;WITH x AS
  (
    SELECT Project_ID, Task_ID, NewTaskID = ROW_NUMBER() OVER (ORDER BY Task_ID)
    FROM dbo.TBL_1 WHERE Project_ID = @Project_ID
  )
  UPDATE x SET Task_ID = NewTaskID;

  COMMIT TRANSACTION;
END
GO

现在,这样称呼它:

EXEC dbo.RenumberTasksWithRedundantInformation 
  @Project_ID  = 1, 
  @FirstTaskID = 2, 
  @LastTaskID  = 4;

然后运行查询:

SELECT Project_ID, Task_ID, Description FROM dbo.TBL_1 WHERE Project_ID = 1;

结果:

Project_ID  Task_ID  Description
----------  -------  -----------
1           1        Task 1
1           2        Task 5
1           3        Task 6

清理:

DROP TABLE dbo.TBL_1;

现在,我的意思是……

...一旦创建此Task_ID 列,就没有真正的理由更新它。您试图将数据库中的标识符和前端代码中的显示项视为同一事物。为什么你不能把这个查询交给你的前端代码:

SELECT Task_ID, SequentialID = ROW_NUMBER() OVER (ORDER BY Task_ID),
  Description FROM dbo.TBL_1 WHERE Project_ID = 1;

现在,UI 可以显示 SequentialID 列,但是当它传回 ID 以更新/删除/你有什么时,它会传递存储在数据库中的实际 Task_ID(你的网格没有'不必关心,哪些用户不应该知道)。这是一个额外的抽象层,但它可以防止您的表格中出现大量不必要的混乱。

我不知道的是,当人们想要删除任务 1、3 和 12,或者交换任务 5 和 6 时,你打算做什么......

【讨论】:

  • 您的观点肯定有效。我需要对这种情况进行一些测试。我对你关于 TASK_ID 相关性的观点感到兴奋,现在我非常担心我的设计的其余部分,因为我认为它存在缺陷。现在测试一下。
  • 是的,ROW_NUMBER() over(按 ID 排序)将不起作用,因为 TASK_ID 列需要以用户预期的正确顺序显示 TASKS。
  • @Wiley 然后更改您的列名,因为它根本不是 TASK_ID,而是 DisplayOrder。我的大粗体免责声明上方的代码仍然可以执行您想要的操作(当您删除多行时)。对于其他用例,我认为您需要提出另一个问题。
  • ROW_NUMBER() over(按 TASK_ID 排序)是多余的。如果用户在 task_id 5 和 6 之间插入,task_id 6 必须更改为 7,以便 task_id 6 可用于行插入。
  • 是 displayOrder 更好
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-07
  • 1970-01-01
  • 1970-01-01
  • 2013-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多