Sql server 触发器中每个循环的t-sql

Sql server 触发器中每个循环的t-sql,sql-server,database,tsql,foreach,Sql Server,Database,Tsql,Foreach,我有一张有字段的桌子。每个字段都属于一个组,每个字段都有一个字段顺序。 例如: 如果我将组1的field3设置为fieldorder=2,则field2需要自动设置为fieldorder=3 如果我将field1移动到fieldorder 3,则field3将是fieldorder=2,field2需要是fieldorder=1 我本想用foreach循环来实现这一点,但似乎找不到。我会稍微改变处理方法,主要是因为我不喜欢触发器,并且使用存储过程。我假设GroupName和FieldName在您

我有一张有字段的桌子。每个字段都属于一个组,每个字段都有一个字段顺序。 例如:

如果我将组1的field3设置为fieldorder=2,则field2需要自动设置为fieldorder=3

如果我将field1移动到fieldorder 3,则field3将是fieldorder=2,field2需要是fieldorder=1


我本想用foreach循环来实现这一点,但似乎找不到。我会稍微改变处理方法,主要是因为我不喜欢触发器,并且使用存储过程。我假设GroupName和FieldName在您的表中是唯一的,并且是主键,否则需要稍微修改以下内容

因此,您的第一个步骤是创建新记录:

CREATE PROCEDURE dbo.InsertT
    @GroupName  VARCHAR(50),
    @FieldName  VARCHAR(50)
AS
BEGIN
    INSERT dbo.T (GroupName, FieldName, FieldOrder)
    SELECT  @GroupName, 
            @Field,
            ISNULL(MAX(FieldOrder), 0)  + 1
    FROM    dbo.T
    WHERE   GroupName = @GroupName;

END
然后是更新FieldOrder的过程:

CREATE PROCEDURE dbo.ChangeFieldOrder
    @GroupName  VARCHAR(50),
    @FieldName  VARCHAR(50),
    @FieldOrder INT
AS
BEGIN
    UPDATE  T
    SET     FieldOrder = CASE WHEN t.FieldName = @FieldName THEN @FieldOrder
                            ELSE t.FieldOrder + c.Motion
                        END
    FROM    (   SELECT  *,
                        Motion = SIGN(FieldOrder - @FieldOrder),
                        LowerVal = CASE WHEN @FieldOrder > FieldOrder THEN FieldOrder ELSE @FieldOrder END,
                        UpperVal = CASE WHEN @FieldOrder > FieldOrder THEN @FieldOrder ELSE FieldOrder END
                FROM    dbo.T 
                WHERE   GroupName = @GroupName
                AND     FieldName = @FieldName
            ) AS c
            INNER JOIN dbo.T AS T
                ON T.GroupName = c.GroupName
    WHERE   Motion != 0 
    AND     t.FieldOrder BETWEEN c.LowerVal AND c.UpperVal;
END
然后,您可以按如下方式运行其中的每一项:

EXECUTE dbo.InsertT 'Group 1', 'Field1';
EXECUTE dbo.InsertT 'Group 1', 'Field2';
EXECUTE dbo.InsertT 'Group 1', 'Field3';
EXECUTE dbo.ChangeFieldOrder 'Group 1', 'Field3', 2;
更新的前提是,仅受影响的行是新旧字段顺序之间的行。子查询c具有以下表达式,这些表达式基本上指示更新:

Motion = SIGN(FieldOrder - @FieldOrder),
LowerVal = CASE WHEN @FieldOrder > FieldOrder THEN FieldOrder ELSE @FieldOrder END,
UpperVal = CASE WHEN @FieldOrder > FieldOrder THEN @FieldOrder ELSE FieldOrder END
LowerVal和UpperVal只是计算出更新的上限和下限,因此可以在WHERE子句中使用以下内容:

Motion,只是计算出其他值需要以哪种方式移动,也就是说,如果你降低一个值的顺序,那么它的旧值和新值之间的每一个值都需要增加1以在序列中留出空间,如果你增加一个记录的顺序,那么你需要将其上的所有值都移动,将新值上下移动1以为其留出空间

使用存储过程进行管理的另一个原因是,它强制以独立方式进行更新,保持规则的简单性,即,如果有人刚刚运行以下命令,您将如何管理触发器:

UPDATE  dbo.T
SET     fieldOrder = 1;
新的订单是什么?如果需要,这种方法还允许使用唯一约束,以确保FieldOrder在每个组中都是唯一的:

ALTER TABLE dbo.T ADD CONSTRAINT UQ_T__GroupName_FieldOrder UNIQUE (GroupName, FieldOrder);

将字段顺序更改为十进制9,1

如果你想让它走到最后 设置fieldorder=4,其中fieldname='field2'

如果你想让它先走一步 设置fieldorder=0,其中fieldname='field2'

如果你想要第二个 设置fieldorder=1.5,其中fieldname='field3'

update table 
   set table.fieldorder = updateorder.newOrder
  from table
  join (select fieldname, row_number() over (order by fieldorder) as newOrder
          from table 
         where groupname = 'group 1') as updateorder
    on updateOrder.fieldname = table.fieldname 
   and table.fieldorder <> updateorder.newOrder
   and table.groupname = 'group 1'
在已发布的评论中,无法更改字段类型 你可以用integer

更新表集合fieldorder=fieldorder*2 然后回答如上所述,但你使用的是奇数整数而不是.5 您可能希望将其全部打包到一个事务中
我知道不漂亮,但问题不漂亮

每当在关系数据库系统中执行某项操作时,试图避免使用基于行/基于迭代的术语进行思考,您描述的问题也可以使用基于集合的操作来解决。但是如何解决,因为fieldorder不是默认值,它是由其他字段顺序生成的。首先,我认为您需要解释更新应该如何工作的明确规则:您总是希望更新共享刚刚更新的条目组的其他条目,但我还不了解更新的方式。我假设fieldorder在同一组中的所有字段中都是唯一的?但目标fieldorder值是如何确定的?您提供的两个示例并不涵盖所有情况,您能更一般地解释其中的规则吗?fieldorder在每个组中都是唯一的,fieldname是主键。因此,每当我更改1个字段的顺序时,所有其他字段都需要根据更改的字段顺序自动更改其顺序。所以每个组都有1,2,3等顺序。。例如,您可以将顺序为23的字段更改为顺序2。所有字段都将更改为1,2,3,4,…,50。所以不会有重复的字段顺序根据更改的字段顺序更改他们的顺序,这是我不理解的;在你的例子之后,顺序似乎是任意的。更新后的第一个示例是field1 order 1;字段2顺序3;字段3顺序2和第二个示例字段1顺序3;字段2顺序1;字段3顺序2;,您只是想确保每个组字段星座的字段顺序是唯一的,还是顺序实际上很重要?它似乎不起作用,它表示受影响的行数为0。我的数据库中的主键是fieldname和pagename。一个页面中有多个具有唯一名称的组。所以我有一个唯一的pagename,它包含多个唯一的组,其中包含唯一的字段。但主键在pagename和fieldname上。请用CREATETABLE语句更新您的问题,这样我可以确保我使用的结构与您相同。我发布的查询在我的测试中运行良好,因此我只能假设在调整我的查询以适合您的表时出现了问题?谢谢,我正在使用一个存储库,我没有资格更改数据类型。你可以把这个细节放在问题中
ALTER TABLE dbo.T ADD CONSTRAINT UQ_T__GroupName_FieldOrder UNIQUE (GroupName, FieldOrder);
update table 
   set table.fieldorder = updateorder.newOrder
  from table
  join (select fieldname, row_number() over (order by fieldorder) as newOrder
          from table 
         where groupname = 'group 1') as updateorder
    on updateOrder.fieldname = table.fieldname 
   and table.fieldorder <> updateorder.newOrder
   and table.groupname = 'group 1'