管理排序

时间:2018-01-18 17:55:17

标签: sql sql-server tsql

我希望我的应用程序的用户使用名为Order的字段更改记录的顺序。我生成了一些脚本以便更改记录的顺序,但我认为应该有更优化的方法来完成它。

我的测试表名为MyTable。表的ID称为ID,订单字段称为Order。

我的SQL命令如下:

上移

Declare @ID int = 3;
Declare @Order int = (SELECT [Order] FROM MyTable WHERE ID = @ID);
Declare @PreviousID int = (SELECT MAX(ID) FROM MyTable WHERE [Order] < @Order);
Update MyTable SET [Order] = @Order - 1 WHERE ID = @ID;
Update MyTable SET [Order] = @Order WHERE ID = @PreviousID

下移

Declare @ID int = 3;
Declare @Order int = (SELECT [Order] FROM MyTable WHERE ID = @ID);
Declare @NextID int = (SELECT MIN(ID) FROM MyTable WHERE [Order] > @Order);
Update MyTable SET [Order] = @Order + 1 WHERE ID = @ID;
Update MyTable SET [Order] = @Order WHERE ID = @NextID

转到顶部

Declare @ID int = 3;
Declare @MinimumOrder int = (SELECT Min([Order]) FROM MyTable);
Update MyTable SET [Order] = @MinimumOrder - 1 WHERE ID = @ID;

移到底部

Declare @ID int = 3;
Declare @MaximumOrder int = (SELECT Max([Order]) FROM MyTable);
Update MyTable SET [Order] = @MaximumOrder + 1 WHERE ID = @ID;

这些SQL命令没有问题。它也可以为Order字段设置负数。

我还想生成一个更新Order文件的SQL脚本,以便它更新Order文件,以便Order从1开始并将其值增加1.这很有用,因为有时我们可能会删除记录或我的脚本可能会产生负序号码。例如,如果您尝试使用Order = 1向上移动记录,那么它将使Order取值0,如果再次执行,则取值-1等。

4 个答案:

答案 0 :(得分:1)

如果您将排序列标准化为从1项目数的值,则可以使用下面的示例代码来维护订单。一般技术是选择where语句的update子句中的所有受影响的行,并使用case表达式来适当地更新排序列。

-- Sample data.
declare @Samples as Table ( SampleId Int Identity, DisplayOrder Int, Name VarChar(20) );
insert into @Samples ( DisplayOrder, Name ) values
  ( 1, 'Chutney' ), ( 2, 'Marshmallows' ), ( 3, 'Carrots' ), ( 4, 'Cheddar' );

select * from @Samples order by DisplayOrder;

-- Swap display orders so that the target row is moved to the target display position.
declare @TargetId as Int = 2;
declare @TargetDisplayOrder as Int = 1;

update @Samples
  set DisplayOrder = case
    when SampleId = @TargetId then @TargetDisplayOrder
    else ( select DisplayOrder from @Samples where SampleId = @TargetId ) end
  where SampleId in ( @TargetId,
    ( select SampleId from @Samples where DisplayOrder = @TargetDisplayOrder ) );

select * from @Samples order by DisplayOrder;

-- Move the target row up one position in the display order.
set @TargetId = 3;

update @Samples
  set DisplayOrder = case
    when SampleId = @TargetId then DisplayOrder - 1
    else DisplayOrder + 1 end
  where SampleId in ( @TargetId,
    ( select SampleId from @Samples where DisplayOrder =
      ( select DisplayOrder from @Samples where SampleId = @TargetId ) - 1 ) );

select * from @Samples order by DisplayOrder;

-- Move the target row down one position in the display order.
set @TargetId = 2;

update @Samples
  set DisplayOrder = case
    when SampleId = @TargetId then DisplayOrder + 1
    else DisplayOrder - 1 end
  where SampleId in ( @TargetId,
    ( select SampleId from @Samples where DisplayOrder =
      ( select DisplayOrder from @Samples where SampleId = @TargetId ) + 1 ) );

select * from @Samples order by DisplayOrder;

-- Move the target row up to the top in the display order.
set @TargetId = 1;

update @Samples
  set DisplayOrder = case
    when SampleId = @TargetId then 1
    else DisplayOrder + 1 end
  where DisplayOrder <= ( select DisplayOrder from @Samples where SampleId = @TargetId );

select * from @Samples order by DisplayOrder;

-- Move the target row down to the bottom in the display order.
set @TargetId = 3;

update @Samples
  set DisplayOrder = case
    when SampleId = @TargetId then ( select Max( DisplayOrder ) from @Samples )
    else DisplayOrder - 1 end
  where DisplayOrder >= ( select DisplayOrder from @Samples where SampleId = @TargetId );

select * from @Samples order by DisplayOrder;

请注意,如果您使用多个语句来执行工作,例如insert新行,然后update将其移动到所需的顺序,您需要将语句包装在事务中(具有合适的隔离级别),以防止多个用户破坏数据。

答案 1 :(得分:0)

我不知道这是否是最好的方法,但我设法使用游标。

DECLARE @i int = 1;
DECLARE @ID int

DECLARE db_cursor CURSOR FOR  
SELECT ID FROM MyTable ORDER BY [Order]

OPEN db_cursor   
FETCH NEXT FROM db_cursor INTO @ID

WHILE @@FETCH_STATUS = 0   
BEGIN   
    update MyTable set [Order] = @i WHERE ID = @ID;
    SET @i = @i + 1;
       FETCH NEXT FROM db_cursor INTO @ID   
END   

CLOSE db_cursor   
DEALLOCATE db_cursor

如果有更好的方法,请通知我。

答案 2 :(得分:0)

在合并订单价值方面,T-SQL的ROW_NUMBER()操作可能对您有用。

这是一个示例,说明如何使用此功能整合订单值,而不会影响该订单中商品的排名:

/* declare placeholder and populate with test values */
declare @MyTable table (ID bigint identity(1,1), [Order] bigint)

insert into @MyTable ([Order]) 
VALUES
(1),
(3),
(2),
(5),
(-4),
(13),
(0)

/* Look at values we've just inserted */
select * from @MyTable order by [Order]

/* Show how ROW_NUMBER() can apply a consolidated ranking based on our existing order */
select *, ROW_NUMBER() over (order by [Order] asc) as sort from @MyTable

/* Apply that consolidated ranking to update the order values */
update @MyTable
set [Order] = consolidated.sort
from 
(
select ID as refID, ROW_NUMBER() over (order by [Order] asc) as sort from @MyTable
) consolidated
where consolidated.refID = ID

/* Final display of updated table */
select * from @MyTable order by [Order]

理想情况下,从一开始就需要花些时间来管理和保持数据清理。

部分内容是数据库结构和规范化,请查看以下内容:

  • 记录是否存在且无法订购?
  • 如果有多个用户,他们都使用相同的订单,还是每个用户都有单独的订单排名?
  • 用户是否可能有多个订单 想用和切换?

如果其中任何一个属实,您可能希望将排序分解为单独的表以用于数据完整性目的(并且由于事务锁定和事情,即使您不这样做也可能值得做)

除了数据库设计之外,还有必要了解如何处理数据操作以修改记录顺序。

如果我们使用具有N条记录的表格,并且这些记录具有密集的订单(根据上面的查询演示,订单值为1,2,3,4,5等) 。),然后任何时候我们对该订单进行了更改,我们必须更新表中现有订单值的很多

例如:

  • 用户修改记录,使其顺序从5变为2.我们现在必须将每条记录从订单2开始转移到订单的末尾。

补偿这一点的一种方法是使用抵消计算排名 - 而不是按1,2,3...排序,而是使用更大的值,例如10,20,30...。这使您可以处理用户的订购更改而无需立即加载大量数据(将订单移至订单2?将其插入位置15,介于10和20之间),然后您可以稍后优化订单。 / p>

答案 3 :(得分:-1)

以下不会获得[订单]中的上一项(除非运气好)。

String SERVICE_URL = "http://hostIpAddress:8080/JiraUpdate/rest/createin/jira/createticket?"; // hostIpaddress is our server ip
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
System.out.println("SERVICE_URL=" + SERVICE_URL);
WebResource webResource = client.resource(UriBuilder.fromUri(SERVICE_URL).build());
String input = "{\"fields\":{\"project\":{\"key\":\"Invoicing\"},\"summary\":\"REST Test\",\"description\": \"Creating of an issue using project keys and issue type names using the REST API\",\"issuetype\":{\"name\":\"Bug\"}}}";

ClientResponse response = webResource.header("Content-Type","application/json;charset=UTF-8").post(ClientResponse.class,input);

Declare @PreviousID int = (SELECT MAX(ID) FROM MyTable WHERE [Order] < @Order); 相同的问题。