Обновите список вещей, не поражая каждую запись

У меня есть список в базе данных, которую пользователь должен смочь заказать.

itemname|  order value (int)
--------+---------------------         
salad   |  1
mango   |  2
orange  |  3
apples  |  4

На загрузке из базы данных, я просто order by order_value.

Перетаскиванием он должен смочь переместиться apples так, чтобы это появилось наверху списка..

itemname|  order value (int)
--------+---------------------         
apples  |  4
salad   |  1
mango   |  2
orange  |  3

Хорошо. Таким образом, теперь внутренне я должен обновить КАЖДЫЙ ЭЛЕМЕНТ СПИСКА! Если список имеет 20 или 100 объектов, это - много обновлений для простой операции перетаскивания.

itemname|  order value (int)
--------+---------------------         
apples  |  1
salad   |  2
mango   |  3
orange  |  4

Я сделал бы это только с одним обновлением. Одним путем я думал, то, если "внутренний Порядок" является a double значение.

itemname|  order value (double)
--------+---------------------         
salad   |  1.0
mango   |  2.0
orange  |  3.0
apples  |  4.0

ТАКИМ ОБРАЗОМ, после перетаскивания n' отбрасывают операцию, я присваиваюсь apples имеет значение, которое является меньше, чем объект, перед которым это должно появиться:

itemname|  order value (double)
--------+---------------------         
apples  |  0.5
salad   |  1.0
mango   |  2.0
orange  |  3.0

.. и если объект перетаскивается в середину куда-нибудь, order_value больше, чем тот, который это появляется после.. здесь я переместился orange быть между salad и mango:

itemname|  order value (double)
--------+---------------------         
apples  |  0.5
salad   |  1.0
orange  |  1.5
mango   |  2.0

Какие-либо мысли о лучших способах сделать это?

6
задан Juan Mellado 4 May 2012 в 12:31
поделиться

5 ответов

Вы можете сделать это с помощью одного оператора Update, например, так:

Update Table
Set OrderValue = Case
                    When Table.ItemName = 'apples' Then 0
                    Else    (
                            Select Count(*)
                            From Table As T1
                            Where T1.ItemName <> 'apples'
                                And T1.OrderValue < Table.OrderValue
                            ) + 1
                    End + 1

Очевидно, вы замените яблок выбранным значением. Однако я думаю, что этот тип сортировки лучше всего выполнять в клиентском приложении, а не в базе данных.

0
ответ дан 17 December 2019 в 18:11
поделиться

Если бы вы использовали SQL Server, вы могли бы сделать это, используя представление связного списка и CTE. Я не знаю, поддерживает ли mysql CTE ...

SET NOCOUNT ON
GO

DROP TABLE [Item]
GO

CREATE TABLE [Item]
(
    [ItemId] int NOT NULL PRIMARY KEY,
    [Name] varchar(100) NOT NULL,
    [PreviousId] int NULL
)
GO

INSERT [Item] VALUES (6, 'apples', 3)
INSERT [Item] VALUES (3, 'orange', 36)
INSERT [Item] VALUES (9, 'mango', 100)
INSERT [Item] VALUES (100, 'salad', NULL)
INSERT [Item] VALUES (36, 'banana', 9)
GO

;WITH
[LinkedItem] AS
(
    SELECT
        [Item].*,
        1 AS [OrderValue]
    FROM [Item]
    WHERE [Item].[PreviousId] IS NULL
    UNION ALL
    SELECT
        [Item].*,
        [LinkedItem].[OrderValue] + 1
    FROM [Item]
        INNER JOIN [LinkedItem] ON [LinkedItem].[ItemId] = [Item].[PreviousId]
)
SELECT *
FROM [LinkedItem]
ORDER BY
    [LinkedItem].[OrderValue]

-- Drag orange up two spaces
DECLARE @MovingItemId int
DECLARE @NewPreviousId int
SET @MovingItemId = 3
SET @NewPreviousId = 100

DECLARE @OldPreviousId int
SELECT @OldPreviousId = [PreviousId] FROM [Item] WHERE [ItemId] = @MovingItemId
UPDATE [Item] SET [PreviousId] = @OldPreviousId WHERE [PreviousId] = @MovingItemId
UPDATE [Item] SET [PreviousId] = @MovingItemId WHERE [PreviousId] = @NewPreviousId
UPDATE [Item] SET [PreviousId] = @NewPreviousId WHERE [ItemId] = @MovingItemId

Это дает следующие результаты до и после:

100 salad  NULL    1
9   mango  100 2
36  banana  9   3
3   orange  36  4
6   apples  3   5

100 salad   NULL    1
3   orange  100 2
9   mango   3   3
36  banana  9   4
6   apples  36  5
0
ответ дан 17 December 2019 в 18:11
поделиться
  1. Как было предложено ранее, и если вам не нужно показывать всем пользователям текущий порядок, на который влияет данный пользователь, я бы предложил сначала обработать это в клиенте (есть много способов решения этой проблемы), а затем, основываясь на действии пользователя (нажатие кнопки "Я закончил", например), обновить строки в базе данных окончательным порядком из структуры, которую вы выбрали для хранения в клиенте.

  2. Вы можете сделать код в клиенте настолько сложным, насколько хотите, чтобы попытаться минимизировать количество строк, которые необходимо обновить в базе данных: в некоторых случаях вам может понадобиться вставить только одну строку (если пользователь вставляет новый элемент в конец списка); во многих случаях вам может понадобиться обновить две строки (если пользователь просто меняет местами два последовательных элемента). Наихудший сценарий с точки зрения количества строк, которые необходимо обновить, - это все строки (вы можете создать алгоритм, который будет определять только те строки, которые необходимо обновить, и обновлять только их). Выбор за вами - стоит ли делать это или просто выпустить обновление всех строк.

  3. Суть в том, что вам не нужно обновлять все строки в базе данных, эта ситуация - лишь один из многих возможных сценариев. Некоторые базы данных позволяют выполнять обновление в массовом порядке (название может отличаться в зависимости от базы данных), и это не будет стоить очень дорого.

0
ответ дан 17 December 2019 в 18:11
поделиться

Я предполагаю, что у вас есть первичный ключ в вашей таблице, столбец id. Эти два утверждения должны сработать.

update table set order_value=0 where itemname='apples';
update 
(select @num := 0 )vars
straight_join 
(select id, @num := @num+1 as ord_value
from table 
order by order_value
)big
inner join table t on t.id = big.id
set t.order_value = big.ord_value;

Если у вас нет id, используйте вместо него itemname.

0
ответ дан 17 December 2019 в 18:11
поделиться

Я не уверен, что это можно считать решением, но буквально не нужно делать одно обновление для каждой строки. Если вы переместите 'foo' из позиции 4 в позицию 1, вы просто сделаете

UPDATE table SET position = 1 WHERE itemname = 'foo'
UPDATE table SET position = position + 1 WHERE itemname != 'foo' AND position < 4

Это то же количество обновлений, даже если вы перемещаетесь с позиции 1000 на 500 или с 500 на 1000 (хотя вам нужно перевернуть это, естественно), вам просто нужно массово сдвинуть все затронутые строки на плюс-минус один

0
ответ дан 17 December 2019 в 18:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: