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

时间:2014-11-26 10:40:53

标签: sql-server database tsql foreach

我有一张带有字段的表格。每个字段属于一个组,每个字段都有一个Field_order。 例如:

groupname  | fieldname | fieldorder
-----------------------------------
group 1    | field1    | 1
group 1    | field2    | 2
group 1    | field3    | 3
group 2    | field4    | 1
group 3    | field5    | 1
group 3    | field6    | 2

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

如果我将field1移至fieldorder 3field3fieldorder = 2field2需要fieldorder = 1,则同样如此。

我想用foreach循环来做这件事,但我似乎无法找到它。

2 个答案:

答案 0 :(得分:0)

我会稍微改变一下,主要是因为我不喜欢触发器,并且使用存储过程。我假设(GroupNameFieldName)在您的表格中是唯一的,并且是主键,否则需要稍微调整以下内容。

所以你的第一个程序是创建新记录:

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

LowerValUpperVal只是计算更新的上限和下限,以便在WHERE子句中使用以下内容:

t.FieldOrder BETWEEN c.LowerVal AND c.UpperVal;

运动,只是计算出其他值需要移动的方式,即如果你减少一个值的顺序,那么它之间的所有旧值和它的新值都需要增加1在序列中创建空格,如果你增加一个记录的顺序,那么你需要将它上面的所有东西都移动,直到新的值减去一个为它腾出空间。

使用存储过程来管理这个问题的另一个原因是它强制更新是单独完成的,保持规则简单,即如果有人刚刚运行,你将如何管理触发器:

UPDATE  dbo.T
SET     fieldOrder = 1;

新订单会是什么?如果需要,此方法还允许使用唯一约束,以确保FieldOrder在每个组中都是唯一的:

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

答案 1 :(得分:0)

将fieldorder更改为小数(9,1)

如果你想要它去最后一次 set fieldorder = 4 where fieldname ='field2'

如果你想要它先去 set fieldorder = 0 where fieldname ='field2'

如果你想要它第二个 set 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'

在评论OP发布时无法更改字段类型
你可以用整数

来做

更新表设置fieldorder = fieldorder * 2
然后是上面发布的答案,但你使用的是奇数,而不是.5
你想把它全部包装在一个交易中 我知道不漂亮,但问题不是很好