2012-07-12 22 views
6

Tôi đang làm việc về quản lý danh mục. Nơi tôi có parentId với mỗi hàng. Danh mục có thể là cấp độ n. Tôi có thể đệ quy gọi hàm php sẽ trả về mảng cây thể loại.Truy vấn Mysql trả về danh mục cây

enter image description here

Bây giờ Issue là: Trong bảng quản trị tôi muốn trang danh sách hạng mục như hình dưới đây. tức là danh mục nào dưới đó.

  • Home
  • Sản phẩm (Chỉnh sửa) (Xóa)
  • Sản phẩm> Sản phẩm 1 (Chỉnh sửa) (Xóa)
  • Sản phẩm> Sản phẩm 2 (Chỉnh sửa) (Xóa)
  • Sản phẩm> Sản phẩm 2 > Sản phẩm 2 1 (chỉnh sửa) (Xóa)
  • Sản phẩm> Sản phẩm 2> Sản phẩm 2 2 (chỉnh sửa) (Xóa)
  • Liên hệ (chỉnh sửa) (Xóa)

Tôi muốn kết quả truy vấn mysql theo thứ tự như được hiển thị ở trên. Tôi không chắc làm thế nào tôi có thể đạt được nó.

SELECT * 
FROM tbl_categories 
ORDER BY ??? 

Vui lòng hướng dẫn.

+0

Better sử dụng cho nó máy chủ ngôn ngữ pgoramming. – Oyeme

+0

Nó đang làm việc với lập trình. Có thể phân trang trong danh sách, tôi muốn sử dụng giới hạn với truy vấn đó. Một nơi nào đó trong giỏ mua sắm mà tôi đã thấy, nhưng tôi không nhớ họ đã làm thế nào. – VibhaJ

+0

hãy cho chúng tôi biết cấu trúc bảng, ví dụ: Cho phép nói, tôi muốn 2 có được hàng Sản phẩm 2.1 –

Trả lời

0

Bạn không thể đạt được điều này trong một truy vấn mysql đơn lẻ. Vâng, bạn có thể đạt được điều này, bằng cách thực hiện nhiều truy vấn. Thuật toán diễn ra như sau: Ban đầu tạo đối tượng tập dữ liệu mà bạn sẽ điền, bằng cách tìm nạp dữ liệu từ cơ sở dữ liệu. Tạo một phương thức lấy id cha làm tham số và trả về các nút con của nó nếu có, và trả về -1, nếu nó không có con. Bước 1: Tìm nạp tất cả các hàng không có nút cha (gốc). Bước 2: Lặp lại kết quả này. Ví dụ: nếu prod1 và prod2 là các nút được trả lại ban đầu, trong resultset. Lặp lại RS này, chúng ta sẽ nhận prod1 và chèn một hàng vào obj DataSET của chúng ta. Sau đó, chúng tôi gửi id của prod1 để getCHILD phương pháp, để có được con của nó, và sau đó một lần nữa chúng tôi lặp lại resultset trả về, và một lần nữa gọi phương thức getCHILD, cho đến khi chúng tôi không nhận được nút thấp nhất.

2

Không có truy vấn SQL đơn có thể mang lại Kết quả cho bạn theo cách bạn mong đợi dựa trên cấu trúc bảng này.

Có hai cách giải quyết vấn đề này:

  1. Sử dụng bên ngoài logic ứng dụng (bên ngoài của DB) để thực hiện cuộc gọi đệ quy đó sẽ khám phá ra con cái của mỗi thể loại và xây dựng cây trong ứng dụng.

  2. Sử dụng một trong các thuật toán để lưu trữ dữ liệu cây trong cơ sở dữ liệu quan hệ. Một trong các thuật toán đó được gọi là Modified Preorder Tree Traversal hoặc đơn giản là MPTT.

Giả sử chúng ta sử dụng các cột lftrgt để duy trì chỉ số trái/phải ở traversal, khi bạn chèn một loại mới, bạn sẽ cần phải:

  1. Nhận thông tin chủ đề chính của Id: SELECT lft,rgt FROM tbl_categories WHERE categoryId=5 Ví dụ, giả sử rằng danh mục gốc có lft=7rgt=10 (trong trường hợp này nó đã có một con)

  2. M ake chỗ cho một mục mới - chuyển tất cả hồ sơ của 2 (1 cho lft và 1 cho rgt):

    UPDATE tbl_categories SET rgt=rgt+2 WHERE rgt>=10 ORDER BY rgt DESC

    UPDATE tbl_categories SET lft=lft+2 WHERE lft>=10 ORDER BY lft DESC

Lưu ý đây ORDER giảm dần. Vì lftrgt được coi là duy nhất, nên thực hiện ràng buộc UNIQUE đối với chúng và sau đó giảm dần thứ tự cập nhật là cần thiết để ngăn chặn các lỗi khóa trùng lặp.

  1. Set lft=<former parent rgt>rgt=<former parent rgt +1> và chèn một kỷ lục mới ...

    INSERT INTO tbl_categories SET categoryName="New Child",parentCategoryId=5,lft=11,rgt=12,...

Bạn có thể tìm thấy ví dụ chi tiết hơn với mã nếu bạn tìm kiếm MPTT PHP MySQL. Có một vài hướng dẫn về chủ đề này.

+0

cảm ơn .. kiểm tra .. – VibhaJ

+3

@VibhaJ: một tùy chọn khác sẽ là một bảng đóng cửa: http://karwin.blogspot.de/2010/03/rendering-trees-with-closure-tables.html có lợi ích bổ sung bạn có thể có khóa ngoài để đảm bảo rằng danh mục gốc thực sự tồn tại. –

+0

Btw, tôi thường sử dụng MPTT trong khi vẫn giữ cha mẹ (và tôi thậm chí thêm chiều sâu) trong bảng, sau đó nó không có một pitfall của việc tìm kiếm người thân ngay lập tức ... – poncha

2

bạn có thể sử dụng chức năng được lưu trữ sẽ đệ quy tìm nạp đường dẫn gốc và nối với cha mẹ của bạn.

DELIMITER $$ 
DROP FUNCTION IF EXISTS `get_category`$$ 
CREATE FUNCTION `get_category`(cat_id int) RETURNS VARCHAR(255) 
READS SQL DATA 
BEGIN 
DECLARE c_id INT; 
DECLARE p_id INT; 
DECLARE count INT; 
DECLARE cat_name VARCHAR(255); 
DECLARE cat_path VARCHAR(255); 
set c_id = cat_id; 
SELECT parent_category_id, category_name INTO p_id, cat_name FROM categories WHERE category_id = c_id; 
set c_id = p_id; 
set cat_path=cat_name; 
set count=0; 
WHILE (c_id IS NOT NULL) DO 

SELECT parent_category_id, category_name INTO p_id, cat_name FROM categories WHERE category_id = c_id; 
set c_id = p_id; 
set cat_path = concat_ws('>',cat_name,cat_path); 
set count = count + 1; 
IF count=10 THEN 
    SET c_id = NULL; 
END IF; 
END WHILE; 
RETURN cat_path; 
END 
$$ 
DELIMITER ; 

và sau đó gọi sử dụng

select getcategory(category_id); 

Herre trong hàm này tôi đã thực hiện một kiểm tra sự tỉnh táo để tránh vòng lặp vô hạn ..

+1

Điều này phát hiện ra đường dẫn cho một danh mục duy nhất, Vì vậy, nếu bạn đang tìm nạp một cây, điều này sẽ yêu cầu gọi cho mỗi kết quả ... Nhưng tốt đẹp anyway;) – poncha

+0

chỉ là một mẫu thử nghiệm, bạn có thể sửa đổi thậm chí này thêm một thủ tục, với một con trỏ, và vòng lặp cho mỗi thể loại cây .. và tiếp tục .. tôi tin rằng nó có thể được thực hiện – satdev86