我有一个带数据的以下SQL表
ProductList
id order productname
79 1 name1
42 2 name2
67 3 somename
88 4 othername
99 5 XYZ
66 6 ABC
显示顺序非常不稳定,它会经常更改,用户会添加或删除项目并重新排序项目。
如何在不更新多条记录的情况下处理这种情况。示例:如果用户输入1到2个订单之间的新产品,我不想更新2以下的所有记录的顺序,如果有人切换订单3到4,我不想更新3以下的每个记录。
答案 0 :(得分:7)
使用由旧BASIC编码器制作的“可怕的旧技巧” - 将您的订单设置为100,200,300,400等,然后您可以在需要时选择“中间”的订单。这可能会变得混乱 - 如果您预计会进行大量的重新排序,那么我建议您有一个计划任务来对整个表格中的订单值进行“重新排序”。
答案 1 :(得分:4)
您有两种选择:
没有SQL功能可以让这更容易,而且没有简单的真正选项。
答案 2 :(得分:4)
同一问题的第二个答案:
使用DOUBLE字段进行排序并拆分要插入的两个值之间的差异。在任何标准的商业应用程序中,我非常非常怀疑你是否会接近无法解决排序顺序差异的插入数量。
答案 3 :(得分:3)
您可以使用字符串代替无数个数字。如果要在“1”和“2”之间插入,请将其设为“15”。
答案 4 :(得分:1)
您可以使用链接列表进行排序(使用某种特殊方式识别头部)。
插入是一个INSERT和一个UPDATE。删除是一个DELETE和一个UPDATE。此举是三次更新。 (当然,使用事务来确保链表不会中断。)
答案 5 :(得分:1)
添加名为OrderDateTime的DATETIME列。使用此列(按降序排列)解决排序中的“关系”,并仅在进行排序操作时更新它。
例如,在您的示例中,假设所有行都具有昨天的OrderDateTime值。
现在,要在1和2之间插入一个项目,你可以将它的Order值设置为2,并将它的OrderDateTime值设置为now。当SELECT * FROM ProductList ORDER BY Order ASC,OrderDateTime DESC时,新的2号项目将在现有项目之前排序。
同样,要交换第4项和第5项,您需要更新第5项,订单为4,OrderDateTime为现在。它将成为一个更近期的4项并且更早出现。
如果您尝试在已经具有相同订单值的其他两个项目之间插入项目,则需要注意分割OrderDateTime值差异。
答案 6 :(得分:0)
在我的情况下,我允许用户重新排序他们的巡演中的步骤。我有一个名为STEP的列,他们可以更改,我创建了一个名为STEP2的列。 STEP2列自动更新为与步骤相同的值。但是当用户更改STEP时,我按照建议的更改和原始顺序(STEP2)DESC进行排序。用户将STEP更新为新值后,我保存到数据库。然后我运行一个proc来重新排序步骤。
proc是:
DECLARE @t StackTable
INSERT INTO @t(Id)
SELECT Id
FROM TourStops
WHERE TourIdRef = @tourId
ORDER BY [Step], [Step2] DESC
UPDATE TourStops
SET [Step] = t.Position, [Step2] = t.Position
FROM TourStops s join @t t on s.Id = t.Id
StackTable是一个包含2列的UDT:Id和Position。 Position是IDENTITY列。每次创建时,它都以1开头,每增加一行,增量为1。
答案 7 :(得分:0)
根据Larry Lustig关于使用双人的建议,我想出了这个。它运行在一个10K行的表中,运行速度非常快。当然欢迎提高效率的建议!
--- Note:
--- [Order] column is a value type of double
--- when inserting into MyTable, set [Order] to
--- MAX([Order])+10
CREATE PROCEDURE dbo.MoveUpLevel
(
@MyTableID int
)
AS
BEGIN
SET NOCOUNT ON
DECLARE @LevelMe float
DECLARE @LevelMin float
DECLARE @LevelMax float
SELECT @LevelMe = [Order]
FROM dbo.MyTable WITH (NOLOCK)
WHERE MyTableID = @MyTableID
SELECT @LevelMin = MIN([Order])
,@LevelMax = MAX([Order])
FROM dbo.MyTable WITH (NOLOCK)
--- Check if already at the top
IF @LevelMe = @LevelMin
RETURN(0)
DECLARE @LevelAboveMe float
SELECT TOP 1 @LevelAboveMe = [Order]
FROM dbo.MyTable WITH (NOLOCK)
WHERE [Order] < @LevelMe
ORDER BY [Order] DESC
DECLARE @LevelAboveMe2 float = 0
IF NOT @LevelAboveMe = @LevelMin
SELECT TOP 1 @LevelAboveMe2 = [Order]
FROM dbo.MyTable WITH (NOLOCK)
WHERE [Order] < @LevelAboveMe
ORDER BY [Order] DESC
-- calculate new level
SET @LevelMe = @LevelAboveMe2 + ((@LevelAboveMe - @LevelAboveMe2)/2)
-- store to DB
UPDATE dbo.MyTable
SET [Order] = @LevelMe
WHERE MyTableID = @MyTableID
RETURN(0)
END
GO
CREATE PROCEDURE dbo.MoveDownLevel
(
@MyTableID int
)
AS
BEGIN
SET NOCOUNT ON
DECLARE @LevelMe float
DECLARE @LevelMin float
DECLARE @LevelMax float
SELECT @LevelMe = [Order]
FROM dbo.MyTable WITH (NOLOCK)
WHERE MyTableID = @MyTableID
SELECT @LevelMin = MIN([Order])
,@LevelMax = MAX([Order])
FROM dbo.MyTable WITH (NOLOCK)
--- Check if already at the bottom
IF @LevelMe = @LevelMax
RETURN(0)
DECLARE @LevelBelowMe float
SELECT TOP 1 @LevelBelowMe = [Order]
FROM dbo.MyTable WITH (NOLOCK)
WHERE [Order] > @LevelMe
ORDER BY [Order] ASC
DECLARE @LevelBelowMe2 float = @LevelMax + 10
IF NOT @LevelBelowMe = @LevelMax
SELECT TOP 1 @LevelBelowMe2 = [Order]
FROM dbo.MyTable WITH (NOLOCK)
WHERE [Order] > @LevelBelowMe
ORDER BY [Order] ASC
-- calculate new level
SET @LevelMe = @LevelBelowMe + ((@LevelBelowMe2 - @LevelBelowMe)/2)
-- store to DB
UPDATE dbo.MyTable
SET [Order] = @LevelMe
WHERE MyTableID = @MyTableID
RETURN(0)
END
GO