transact query language sql sqlite sqlite3 hierarchical-data

query - consulta recursiva básica en sqlite3?



sqlite3 doc (5)

En base a las muestras encontradas en sqlite.org/lang_with.html , la consulta

DROP TABLE IF EXISTS parts; CREATE TABLE parts (part, superpart); INSERT INTO parts VALUES("wk0Z", "wk00"); INSERT INTO parts VALUES("wk06", "wk02"); INSERT INTO parts VALUES("wk07", "wk02"); INSERT INTO parts VALUES("eZ01", "eZ00"); INSERT INTO parts VALUES("eZ02", "eZ00"); INSERT INTO parts VALUES("eZ03", "eZ01"); INSERT INTO parts VALUES("eZ04", "eZ01"); WITH RECURSIVE under_part(parent,part,level) AS ( VALUES(''?'', ''eZ00'', 0) UNION ALL SELECT parts.superpart, parts.part, under_part.level+1 FROM parts, under_part WHERE parts.superpart=under_part.part ) SELECT SUBSTR(''..........'',1,level*3) || "(" || parent || ", " || part || ")" FROM under_part ;

saldría

(?, eZ00) ...(eZ00, eZ01) ...(eZ00, eZ02) ......(eZ01, eZ03) ......(eZ01, eZ04)

como "debería ser" esperado

el registro inicial de la tabla recursiva se puede reemplazar por

VALUES ((SELECT superpart FROM parts WHERE part=''eZ00''), ''eZ00'', 0)

para obtener también el padre de la superpartición inicial, aunque en este caso no hay padre en absoluto.

Tengo una tabla sqlite3 simple que se ve así:

Table: Part Part SuperPart wk0Z wk00 wk06 wk02 wk07 wk02 eZ01 eZ00 eZ02 eZ00 eZ03 eZ01 eZ04 eZ01

Necesito ejecutar una consulta recursiva para encontrar todos los pares de un SuperPart dado con todos sus subParts. Entonces digamos que tengo eZ00. eZ00 es una superparte de eZ01 y eZ01 es una superparte de eZ03. El resultado debe incluir no solo los pares (eZ00, eZ01) y (eZ01 y eZ03), sino también el par (eZ00, eZ03).

Sé que hay otras formas de definir la tabla, pero no tengo otra opción aquí. Sé que puedo usar varias uniones si conozco la profundidad de mi árbol, pero no siempre sabré qué tan profundo quiero ir. Ayudaría tener algo como WITH RECURSIVE o incluso simplemente WITH (,,) AS x pero para lo que he buscado, eso no es posible en sqlite, ¿verdad?

¿Hay alguna manera de hacer esta consulta recursiva en sqlite3?

ACTUALIZAR:

Cuando se hizo esta pregunta, SQLite no admitía las consultas recursivas, pero como lo indica @lunicon , SQLite ahora es compatible con CTE recursivo desde 3.8.3 sqlite.org/lang_with.html



Esta es la consulta más básica que se me ocurrió, genera una serie en la que comenzamos con 1,2 y seguimos agregando 1 hasta llegar a 20. No es muy útil, pero jugar un poco con esto te ayudará a construir recursivas más complejas.

La serie más básica

WITH b(x,y) AS ( SELECT 1,2 UNION ALL SELECT x+ 1, y + 1 FROM b WHERE x < 20 ) SELECT * FROM b;

Huellas dactilares

1|2 2|3 3|4 4|5 5|6 6|7 7|8 8|9 9|10 10|11 11|12 12|13 13|14 14|15 15|16 16|17 17|18 18|19 19|20 20|21

Aquí hay otro ejemplo simple que genera números de Fibonacci: comenzamos con a = 0, b = 1 y luego vamos a = b, b = a + b tal como lo haríamos en cualquier lenguaje de programación

Serie Fibonacci

WITH b(x,y) AS ( SELECT 0,1 UNION ALL SELECT y, x + y FROM b WHERE x < 10000 ) select * FROM b;

Huellas dactilares

0|1 1|1 1|2 2|3 3|5 5|8 8|13 13|21 21|34 34|55 55|89 89|144 144|233 233|377 377|610 610|987 987|1597 1597|2584 2584|4181 4181|6765 6765|10946 10946|17711


Si tiene la suerte de utilizar SQLite 3.8.3 o superior, entonces tiene acceso a CTE recursivos y no recursivos que utilizan sqlite.org/lang_with.html :

Gracias a lunicon por lunicon sobre esta actualización de SQLite.

En versiones anteriores a la 3.8.3 , SQLite no admitía CTE recursivas (o CTE en absoluto), por lo que no había WITH en SQLite . Como no sabes cuán profundo es, no puedes usar el truco JOIN estándar para simular el CTE recursivo. Tienes que hacerlo de la manera difícil e implementar la recursión en tu código de cliente:

  • Agarra la fila inicial y las ID de las subpartes.
  • Tome las filas y las ID de las subpartes para las subpartes.
  • Repite hasta que nada vuelva.

hay un truco http://dje.me/2011/03/26/sqlite-data-trees.html

-- A method for storing and retrieving hierarchical data in sqlite3 -- by using a trigger and a temporary table. -- I needed this but had trouble finding information on it. -- This is for sqlite3, it mostly won''t work on anything else, however -- most databases have better ways to do this anyway. PRAGMA recursive_triggers = TRUE; -- This is not possible before 3.6.18 -- When creating the Node table either use a primary key or some other -- identifier which the child node can reference. CREATE TABLE Node (id INTEGER PRIMARY KEY, parent INTEGER, label VARCHAR(16)); INSERT INTO Node (parent, label) VALUES(NULL, "root"); INSERT INTO Node (parent, label) VALUES(1, "a"); INSERT INTO Node (parent, label) VALUES(2, "b"); INSERT INTO Node (parent, label) VALUES(3, "c1"); INSERT INTO Node (parent, label) VALUES(3, "c2"); -- Create the temp table, note that node is not a primary key -- which insures the order of the results when Node records are -- inserted out of order CREATE TEMP TABLE Path (node INTEGER, parent INTEGER, label VARCHAR(16)); CREATE TRIGGER find_path AFTER INSERT ON Path BEGIN INSERT INTO Path SELECT Node.* FROM Node WHERE Node.id = new.parent; END; -- The flaw here is that label must be unique, so when creating -- the table there must be a unique reference for selection -- This insert sets off the trigger find_path INSERT INTO Path SELECT * FROM Node WHERE label = "c2"; -- Return the hierarchy in order from "root" to "c2" SELECT * FROM Path ORDER BY node ASC; DROP TABLE Path; -- Important if you are staying connected -- To test this run: -- sqlite3 -init tree.sql tree.db