2011-07-23 32 views
26

tôi muốn lưu trữ các thư mục hiện có trên đĩa vào cơ sở dữ liệu với duy trì cấu trúc phân cấp/cây của chúng.cơ sở dữ liệu phân cấp/cây cho các thư mục trong hệ thống tập tin

Dưới đây là một vả,

 
         (ROOT) 
        /  \ 
        Dir2  Dir3 
       / \   \ 
       Dir4 Dir5  Dir6 
       /   
       Dir7 

Tôi đang sử dụng cơ sở dữ liệu SQLite .

  • Vui lòng đề nghị tôi truy vấn sql để lưu trữ cấu trúc trên trong cơ sở dữ liệu SQLite.

  • và truy vấn để truy xuất đường dẫn đầy đủ của thư mục khi tôi chọn một thư mục.

tức Giả sử tôi chọn Dir6 sau đó tôi Linh hồn có được đường dẫn đầy đủ như ROOT/dir2/dir3/dir7

+1

Một bảng đóng cửa có thể là một lựa chọn tốt. Hãy xem [Cách hiệu quả nhất/thanh lịch để phân tích một bảng phẳng thành cây là gì?] (Http://stackoverflow.com/questions/192220/what-is-the-most-efficient-elegant-way- để-parse-a-phẳng-bảng-thành-một-cây # 192462), và cũng xem [Bill Karwin's] (http://stackoverflow.com/users/20860/bill-karwin) trang trình bày trên [Mô hình cho dữ liệu phân cấp ] (http://www.slideshare.net/billkarwin/models-for-hierarchical-data) – Mike

+0

Chủ đề đã xuất hiện trở lại trong danh sách chủ đề SQLite, và Eduardo Morras (lại) đã chỉ ra phần mở rộng vtable SQLite này để xử lý phân cấp từ bản repo SQLite: 1) http://www.sqlite.org/src/artifact/636024302cde41b2bf0c542f81c40c624cfb7012 2) http://www.sqlite.org/src/finfo?name=ext/misc/closure.c – ddevienne

Trả lời

32

Dưới đây là ví dụ về bảng đóng cửa nhanh cho SQLite. Tôi đã không bao gồm các câu lệnh để chèn các mục vào một cây hiện có. Thay vào đó, tôi vừa tạo các câu lệnh theo cách thủ công. Bạn có thể tìm các câu lệnh chèn và xóa trong các trang trình bày Models for hierarchical data.

Vì lợi ích của sự tỉnh táo của tôi khi chèn các ID cho các thư mục, tôi đổi tên các thư mục để phù hợp với ID của họ:

 (ROOT) 
    /  \ 
    Dir2  Dir3 
    / \   \ 
    Dir4 Dir5  Dir6 
/   
Dir7 

Tạo bảng

CREATE TABLE `filesystem` (
    `id` INTEGER, 
    `dirname` TEXT, 
    PRIMARY KEY (`id`) 
); 

CREATE TABLE `tree_path` (
    `ancestor` INTEGER, 
    `descendant` INTEGER, 
    PRIMARY KEY (`ancestor`, `descendant`) 
); 

Chèn danh bạ vào filesystem bảng

INSERT INTO filesystem (id, dirname) VALUES (1, 'ROOT'); 
INSERT INTO filesystem (id, dirname) VALUES (2, 'Dir2'); 
INSERT INTO filesystem (id, dirname) VALUES (3, 'Dir3'); 
INSERT INTO filesystem (id, dirname) VALUES (4, 'Dir4'); 
INSERT INTO filesystem (id, dirname) VALUES (5, 'Dir5'); 
INSERT INTO filesystem (id, dirname) VALUES (6, 'Dir6'); 
INSERT INTO filesystem (id, dirname) VALUES (7, 'Dir7'); 

Tạo các đường dẫn bảng đóng cửa

INSERT INTO tree_path (ancestor, descendant) VALUES (1, 1); 
INSERT INTO tree_path (ancestor, descendant) VALUES (1, 2); 
INSERT INTO tree_path (ancestor, descendant) VALUES (1, 3); 
INSERT INTO tree_path (ancestor, descendant) VALUES (1, 4); 
INSERT INTO tree_path (ancestor, descendant) VALUES (1, 5); 
INSERT INTO tree_path (ancestor, descendant) VALUES (1, 6); 
INSERT INTO tree_path (ancestor, descendant) VALUES (1, 7); 
INSERT INTO tree_path (ancestor, descendant) VALUES (2, 2); 
INSERT INTO tree_path (ancestor, descendant) VALUES (2, 4); 
INSERT INTO tree_path (ancestor, descendant) VALUES (2, 5); 
INSERT INTO tree_path (ancestor, descendant) VALUES (2, 7); 
INSERT INTO tree_path (ancestor, descendant) VALUES (3, 3); 
INSERT INTO tree_path (ancestor, descendant) VALUES (3, 6); 
INSERT INTO tree_path (ancestor, descendant) VALUES (4, 4); 
INSERT INTO tree_path (ancestor, descendant) VALUES (4, 7); 
INSERT INTO tree_path (ancestor, descendant) VALUES (5, 5); 
INSERT INTO tree_path (ancestor, descendant) VALUES (6, 6); 
INSERT INTO tree_path (ancestor, descendant) VALUES (7, 7); 

Chạy một số truy vấn

# (ROOT) and subdirectories 
SELECT f.id, f.dirname FROM filesystem f 
    JOIN tree_path t 
    ON t.descendant = f.id 
WHERE t.ancestor = 1; 

+----+---------+ 
| id | dirname | 
+----+---------+ 
| 1 | ROOT | 
| 2 | Dir2 | 
| 3 | Dir3 | 
| 4 | Dir4 | 
| 5 | Dir5 | 
| 6 | Dir6 | 
| 7 | Dir7 | 
+----+---------+ 


# Dir3 and subdirectories 
SELECT f.id, f.dirname 
    FROM filesystem f 
    JOIN tree_path t 
    ON t.descendant = f.id 
WHERE t.ancestor = 3; 

+----+---------+ 
| id | dirname | 
+----+---------+ 
| 3 | Dir3 | 
| 6 | Dir6 | 
+----+---------+ 

# Dir5 and parent directories 
SELECT f.id, f.dirname 
    FROM filesystem f 
    JOIN tree_path t 
    ON t.ancestor = f.id 
WHERE t.descendant = 5; 

+----+---------+ 
| id | dirname | 
+----+---------+ 
| 1 | ROOT | 
| 2 | Dir2 | 
| 5 | Dir5 | 
+----+---------+ 

# Dir7 and parent directories 
SELECT f.id, f.dirname 
    FROM filesystem f 
    JOIN tree_path t 
    ON t.ancestor = f.id 
WHERE t.descendant = 7; 

+----+---------+ 
| id | dirname | 
+----+---------+ 
| 1 | ROOT | 
| 2 | Dir2 | 
| 4 | Dir4 | 
| 7 | Dir7 | 
+----+---------+ 

SELECT f.id, f.dirname 
    FROM filesystem f 
    JOIN tree_path t 
    ON t.ancestor = f.id 
WHERE t.descendant = (
SELECT id 
    FROM filesystem 
WHERE dirname LIKE '%7%' 
); 

+----+---------+ 
| id | dirname | 
+----+---------+ 
| 1 | ROOT | 
| 2 | Dir2 | 
| 4 | Dir4 | 
| 7 | Dir7 | 
+----+---------+ 
+0

@ JOHN: Xin lỗi, nhưng tôi chưa bao giờ sử dụng orientDB, vì vậy không thể bình luận được. – Mike

+0

@JOHN: Tôi không chắc chắn ý của bạn là gì - xin bạn có thể đưa ra một ví dụ? – Mike

+0

@JOHN: Có một số cách để làm điều đó. Tôi đã thêm một ví dụ khác mà chỉ cần thực hiện một SELECT bổ sung để tìm ID. Bạn cũng có thể làm một JOIN. – Mike

1

Bạn đại diện cho dữ liệu phân cấp như là một loạt các nút mỗi trong số đó có một ID và một ID mẹ . Bạn có thể lưu trữ của bạn trong một bảng gọi là DIRTAB với 2 cột ID và một cho các văn bản của tên thư mục cá nhân:

ID -- as a primary key 
PARENT_ID -- refers to the ID of the parent row in DIRTAB 
DIRNAME -- the text of the name eg Dir5 

SQLite thiếu CONNECT khoản rằng Oracle có để xử lý dữ liệu phân cấp THEO nhưng tôi nghĩ rằng nếu bạn đang chuẩn bị để chấp nhận một số SQL xấu xí bạn có thể xấp xỉ một cái gì đó theo cấp bậc:

SELECT (CASE WHEN p5.DIRNAME IS NOT NULL THEN p5.DIRNAME || '/' ELSE '' END) || 
     (CASE WHEN p4.DIRNAME IS NOT NULL THEN p4.DIRNAME || '/' ELSE '' END) || 
     (CASE WHEN p3.DIRNAME IS NOT NULL THEN p3.DIRNAME || '/' ELSE '' END) || 
     (CASE WHEN p2.DIRNAME IS NOT NULL THEN p2.DIRNAME || '/' ELSE '' END) || 
     (CASE WHEN p1.DIRNAME IS NOT NULL THEN p1.DIRNAME || '/' ELSE '' END) || 
     p0.DIRNAME as FULLPATH 
FROM DIRTAB p0 
    LEFT OUTER JOIN DIRTAB p1 ON p1.ID = p0.PARENT_ID 
    LEFT OUTER JOIN DIRTAB p2 ON p2.ID = p1.PARENT_ID 
    LEFT OUTER JOIN DIRTAB p3 ON p3.ID = p2.PARENT_ID 
    LEFT OUTER JOIN DIRTAB p4 ON p4.ID = p3.PARENT_ID 
    LEFT OUTER JOIN DIRTAB p5 ON p5.ID = p4.PARENT_ID 
WHERE p0.DIRNAME = 'Dir6' 

vấn đề ở đây là bạn phải dự đoán độ sâu tối đa của bạn cấu trúc thư mục và mở rộng câu lệnh SQL để đối phó. Tôi đã làm 6 cấp độ làm ví dụ.
Ngoài ra, tôi giả định rằng SQLite không có vấn đề gì với việc nối chuỗi rỗng. (Một số DB coi chúng là null và chuyển đổi toàn bộ kết quả biểu thức thành null)

1

Tôi nghĩ bạn nên đọc về một phương pháp caled Modified Preorder Tree Traversal: http://www.sitepoint.com/hierarchical-data-database/

Liên kết đó thảo luận về hai phương pháp để toring dữ liệu phân cấp vào cơ sở dữ liệu quan hệ: mô hình danh sách kề và thuật toán duyệt cây duyệt trước được sửa đổi.

Ý tưởng chính của phương pháp Modified Preorder Tree Traversal là chú thích tất cả các nút với các con trỏ tới auxiliate điều hướng và cây con lựa chọn: enter image description here

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