2010-05-13 25 views
5

Tôi có một danh sách trong cơ sở dữ liệu mà người dùng có thể đặt hàng.Cập nhật danh sách mọi thứ mà không cần nhấn vào mỗi mục nhập

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

Khi tải từ cơ sở dữ liệu, tôi chỉ đơn giản là order by order_value.

Bằng cách kéo 'n thả, ông sẽ có thể di chuyển apples để nó xuất hiện ở phía trên cùng của danh sách ..

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

Ok. Vì vậy, bây giờ trong nội bộ tôi phải cập nhật MỌI DANH SÁCH MỤC! Nếu danh sách có 20 hoặc 100 mục, đó là rất nhiều cập nhật cho thao tác kéo đơn giản.

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

Tôi muốn làm điều đó chỉ với một bản cập nhật. Một cách tôi nghĩ là nếu "Lệnh nội bộ" là giá trị double.

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

SO sau khi kéo n' thả hoạt động, tôi gán apples có một giá trị thấp hơn mục đó là để xuất hiện trước nhà:

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

.. và nếu một mục là kéo vào giữa một nơi nào đó, nó order_value lớn hơn một nó xuất hiện sau khi .. đây tôi chuyển orange là giữa saladmango:

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

Bất kỳ suy nghĩ nào về cách tốt hơn để thực hiện việc này?

+3

Nếu đây là dữ liệu do con người tạo, thì tối đa có thể là hàng tá mục. Hầu hết mọi người sẽ mất lãi theo cách thủ công sắp xếp hơn một vài chục (và giao diện người dùng để thực hiện nó sẽ vượt qua khoảng 20 trừ khi bạn có một màn hình lớn thực sự). Vì vậy, chỉ cần làm điều đó. Nó sẽ là một câu chuyện khác nếu bạn đang sử dụng 1000 hoặc hàng triệu mặt hàng. – Seth

+0

Bạn có cần cho phép cập nhật đồng thời không? –

Trả lời

0

Tôi không chắc liệu đây có phải là giải pháp hay không, nhưng bạn không cần thực hiện cập nhật cho mỗi hàng. Nếu bạn di chuyển 'foo' từ vị trí thứ 4 với vị trí 1, bạn chỉ cần làm

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

Đó là cùng một số thông tin cập nhật ngay cả khi bạn đang di chuyển từ vị trí 1000-500, hoặc 500-1000 (mặc dù bạn' sẽ cần phải lật nó, một cách tự nhiên), bạn chỉ cần khối lượng chuyển tất cả các hàng bị ảnh hưởng cộng hoặc trừ một

+0

Vâng, tôi đang tìm số lượng truy cập __worst nhỏ__ số lượt truy cập – bobobobo

+0

@bob Tôi nghĩ có thể bạn đã hiểu lầm; đây là hai bản cập nhật không có vấn đề gì: một để thay đổi hàng thực tế, và một để sửa tất cả các hàng bị ảnh hưởng khác –

0

bạn có thể làm điều đó trong một tuyên bố cập nhật duy nhất như vậy:

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 

bạn rõ ràng là sẽ thay thế apples với giá trị đã chọn. Tuy nhiên, tôi sẽ nghĩ rằng loại phân loại này sẽ được thực hiện tốt nhất trong ứng dụng khách chứ không phải trong cơ sở dữ liệu.

+0

Vì vậy, những gì về một chèn vào giữa danh sách? Tôi cho rằng điều này có thể được đặt trong một thủ tục được lưu trữ và chỉ mục trong danh sách mà 'apples' now" goes "có thể là một đối số. Tôi sẽ làm điều này trong máy khách, nhưng tôi phải phản ánh nó trong cơ sở dữ liệu ngay lập tức trong trường hợp client x ra khỏi trình duyệt, để khung nhìn được nạp theo thứ tự mà client cuối cùng còn lại nó. – bobobobo

+0

@bobobobo - Mã của bạn sẽ xác định "giữa danh sách" để thực hiện chèn như thế nào? Tôi vẫn cho rằng điều này sẽ dễ dàng hơn đáng kể ở tầng giữa so với trong cơ sở dữ liệu. Mã trang web của bạn có thể lưu trữ các giá trị trong một mảng và chỉ cần di chuyển các mục trong mảng cho loại cụ thể. – Thomas

0

Nếu bạn đang sử dụng SQL Server, bạn có thể thực hiện việc này bằng cách sử dụng biểu diễn danh sách liên kết và CTE. Tôi không biết liệu mysql hỗ trợ CTEs dù ...

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 

này tạo ra sau khi kết quả như sau trước và:

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 
+1

AFAIK, MySQL chưa hỗ trợ CTE. – Thomas

+0

@Thomas: chính xác và không hỗ trợ (không chuẩn) [] làm dấu ngoặc kép –

0

Tôi giả sử bạn có một khóa chính trên bảng của bạn, một cột id . Hai câu lệnh này nên làm.

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; 

Nếu bạn không có id, hãy sử dụng tên mục thay thế.

0
  1. Như đã đề xuất trước đó và trừ khi bạn phải hiển thị cho tất cả người dùng thứ tự hiện tại mà người dùng nhất định đang ảnh hưởng, tôi khuyên bạn nên xử lý điều này trong ứng dụng khách trước (có nhiều cách giải quyết điều này), và sau đó, dựa trên hành động của người dùng (nhấn nút "Tôi đã hoàn tất"), bạn cập nhật các hàng trong cơ sở dữ liệu với thứ tự cuối cùng từ cấu trúc mà bạn đã chọn để lưu trữ trong máy khách.

  2. Bạn có thể làm cho mã trong máy khách phức tạp như bạn muốn cố gắng giảm thiểu số hàng cần cập nhật trong cơ sở dữ liệu: trong một số trường hợp, bạn chỉ cần chèn một hàng (nếu người dùng chèn một mục mới vào cuối danh sách); trong nhiều trường hợp, bạn có thể cần phải cập nhật hai hàng (nếu người dùng chỉ hoán đổi hai mục liên tiếp). Kịch bản tồi tệ nhất theo số lượng hàng cần được cập nhật, là tất cả các hàng (bạn có thể thiết lập một thuật toán sẽ chỉ phát hiện các hàng cần được cập nhật và chỉ cập nhật những hàng đó). Sự lựa chọn là của bạn cho dù đó là giá trị làm điều này hoặc chỉ phát hành một bản cập nhật của tất cả các hàng.

  3. Điểm mấu chốt là bạn không cần phải cập nhật tất cả các hàng trong cơ sở dữ liệu, tình huống đó chỉ là một trong nhiều tình huống có thể xảy ra. Một số cơ sở dữ liệu cho phép cập nhật hàng loạt (tên có thể thay đổi từ cơ sở dữ liệu này sang cơ sở dữ liệu khác) và điều này sẽ không tốn kém lắm.

2

Giả sử @old là giá trị 4 cho vị trí cũ của táo, và @new là vị trí mới 1.

set @old = 4; 
set @new = 1; 

UPDATE Items 
SET `order value` = 
    CASE `order value` WHEN @old THEN @new 
    ELSE `order value` + SIGN(@[email protected]) END 
WHERE `order value` BETWEEN LEAST(@old, @new) AND GREATEST(@old, @new); 

tôi sử dụng MySQL 5.1.52 để kiểm tra điều này trên dữ liệu ví dụ của bạn và nó công trinh. SQL giống hệt nhau cũng hoạt động nếu bạn cần di chuyển mục nhập sớm để sau này hoặc di chuyển một mục ở giữa, v.v. Chỉ cần đặt các giá trị @old@new.

0

Nếu cột chỉ đơn giản là chỉ định thứ tự của các hàng, tôi không thấy điều gì sai khi sử dụng 0 và phủ định.

Các vấn đề liên quan