Saya menyimpan hierarki folder dalam Database Sqlite seperti:

+----------+---------+----------+
| ParentID | ChildID |   Name   |
+----------+---------+----------+
|        1 |       2 | Folder A |
|        2 |       3 | Folder B |
|        3 |       4 | Folder C |
+----------+---------+----------+

Dimana Folder A adalah akar dan strukturnya adalah: Folder A/Folder B/Folder C.

Saat ini, saya memiliki CTE Rekursif yang dapat memperoleh jalur folder yang diberikan ID-nya. (Ini bekerja dengan menemukan ID di kolom ChildID dan kemudian berjalan ke atas)

Namun, apa yang saya TIDAK miliki saat ini adalah cara untuk mendapatkan ID folder yang diberikan jalurnya. Ini jelas sedikit lebih rumit karena saya harus membagi string pada / jika saya ingin dapat mengkueri tabel.

Sejauh ini saya sudah memulai CTE Rekursif:

SELECT Path, ChildID FROM DirectoryStructure, (
    SELECT SUBSTR('Folder A/Folder B/Folder C', 0, Position) as Root, 
           SUBSTR('Folder A/Folder B/Folder C', Position+1) as Path 
    FROM (SELECT INSTR('Folder A/Folder B/Folder C', '/') as Position)
) WHERE Name = Root

Ini akan kembali:

+-------------------+---------+
|       Path        | ChildID |
+-------------------+---------+
| Folder B/Folder C |       2 |
+-------------------+---------+

Ini sempurna karena saya memiliki ChildID Folder A dan juga memiliki potongan Path untuk diproses berikutnya. Sekarang hanya masalah melakukan langkah berikutnya secara rekursif di mana saya mencabut Folder B (seperti yang saya lakukan Folder A) dan menemukan entri di DirectoryStructure di mana ParentID = 2 AND Name = 'Folder B' mendapatkannya itu ChildID dan seterusnya.

Namun, di situlah saya mengalami kesulitan. Saya akan membayangkan saya membutuhkan sesuatu seperti ini:

WITH RECURSIVE GetId(Path, LastChild) AS (
    SELECT Path, ChildID FROM DirectoryStructure, (
        SELECT SUBSTR('Folder A/Folder B/Folder C', 0, Position) as Root, 
               SUBSTR('Folder A/Folder B/Folder C', Position+1) as Path 
        FROM (SELECT INSTR('Folder A/Folder B/Folder C', '/') as Position)
    ) WHERE Name = Root
    UNION ALL
    SELECT Path, ChildID FROM DirectoryStructure, (
        SELECT SUBSTR(GetId.Path, 0, Position) as Root, 
               SUBSTR(GetId.Path, Position+1) as Path
        FROM GetId, (SELECT INSTR(GetId.Path, '/') as Position FROM GetId)
    ) WHERE (ParentID = GetId.LastChild, Name = Root)
) SELECT * from GetId;

Bermain-main dengan ini saya biasanya mendapatkan kesalahan: Result: recursive reference in a subquery: GetId

Saya mengerti bahwa itu tidak ingin saya menggunakan GetId di subquery tetapi sepertinya saya tidak dapat menemukan cara lain untuk mencapai ini.

Bantuan apa pun akan sangat dihargai!

0
meci 18 Juni 2020, 07:17

1 menjawab

Jawaban Terbaik

Cara alternatif untuk mendekati ini adalah menemukan jalur ke setiap anak dan kemudian membandingkannya dengan jalur pencarian:

WITH RECURSIVE CTE AS (
  SELECT ChildId, Name AS Path
  FROM DirectoryStructure
  WHERE ParentID = 1
  UNION ALL
  SELECT d.ChildId, Path || '/' || Name
  FROM DirectoryStructure d
  JOIN CTE ON d.ParentId = CTE.ChildId
)
SELECT *
FROM CTE
WHERE Path = 'Folder A/Folder B/Folder C'

Keluaran:

ChildId     Path
4           Folder A/Folder B/Folder C

Demo di dbfiddle

Jika tabel Anda besar dan kueri di atas terlalu lambat, Anda dapat memangkas entri saat Anda pergi untuk memastikan bahwa entri tersebut cocok dengan jalur yang diinginkan hingga tingkat tersebut:

WITH RECURSIVE CTE AS (
  SELECT ChildId, Name AS Path
  FROM DirectoryStructure
  WHERE ParentID = 1
    AND 'Folder A/Folder B/Folder C' LIKE Name || '%'
  UNION ALL
  SELECT d.ChildId, Path || '/' || Name
  FROM DirectoryStructure d
  JOIN CTE ON d.ParentId = CTE.ChildId
  WHERE 'Folder A/Folder B/Folder C' LIKE Path || '/' || Name || '%'
)
SELECT *
FROM CTE
WHERE Path = 'Folder A/Folder B/Folder C'

Demo di dbfiddle

1
Nick 18 Juni 2020, 06:10