Domanda

Ho una tabella simile a questa:

CREATE TABLE example (
  id integer primary key,
  name char(200),
  parentid integer,
  value integer);

Posso utilizzare il campo genitore per organizzare i dati in una struttura ad albero.

Ora ecco la parte che non riesco a risolvere.Dato un genitore, è possibile scrivere un'istruzione SQL per sommare tutti i campi valore sotto quel genitore e ricorsire lungo il ramo dell'albero?

AGGIORNAMENTO: Sto utilizzando posgreSQL quindi le fantasiose funzionalità di MS-SQL non sono disponibili per me.In ogni caso, vorrei che questa fosse trattata come una domanda SQL generica.

A proposito, sono molto colpito dal fatto di avere 6 risposte entro 15 minuti dalla domanda!Vai in overflow dello stack!

È stato utile?

Soluzione

Esistono alcuni modi per fare ciò di cui hai bisogno in PostgreSQL.

Qualcosa come questo:

create or replace function example_subtree (integer)
returns setof example as
'declare results record;
         child record;
 begin
  select into results * from example where parent_id = $1;
  if found then
    return next results;
    for child in select id from example
                  where parent_id = $1
      loop
        for temp in select * from example_subtree(child.id)
        loop
          return next temp;
        end loop;
      end loop;
  end if;
  return null;
end;' language 'plpgsql';

select sum(value) as value_sum
  from example_subtree(1234);

Altri suggerimenti

Ecco uno script di esempio che utilizza un'espressione di tabella comune:

with recursive sumthis(id, val) as (
    select id, value
    from example
    where id = :selectedid
    union all
    select C.id, C.value
    from sumthis P
    inner join example C on P.id = C.parentid
)
select sum(val) from sumthis

Lo script sopra crea una tabella "virtuale" chiamata sumthis che ha colonne id E val.È definito come il risultato di due selezioni unite union all.

Primo select ottiene la radice (where id = :selectedid).

Secondo select segue iterativamente i figli dei risultati precedenti finché non c'è nulla da restituire.

Il risultato finale può quindi essere elaborato come una normale tabella.In questo caso viene sommata la colonna val.

Dalla versione 8.4, PostgreSQL ha supporto per query ricorsive per le espressioni di tabella comuni che utilizzano lo standard SQL WITH sintassi.

Se desideri una soluzione portatile che funzioni su qualsiasi file ANSI SQL-92 RDBMS, dovrai aggiungere una nuova colonna alla tua tabella.

Joe Celko è l'autore originale del Insiemi nidificati approccio alla memorizzazione delle gerarchie in SQL.Puoi Google Gerarchia degli "insiemi nidificati". per capire meglio lo sfondo.

Oppure puoi semplicemente rinominare parentid in sinistra e aggiungi a rightid.

Ecco il mio tentativo di riassumere i Nested Sets, che fallirà tristemente perché non sono Joe Celko:SQL è un linguaggio basato su insiemi e il modello di adiacenza (memorizzazione dell'ID genitore) NON è una rappresentazione di una gerarchia basata su insiemi.Pertanto non esiste un metodo basato su insiemi puro per interrogare uno schema di adiacenza.

Tuttavia, negli ultimi anni la maggior parte delle principali piattaforme ha introdotto estensioni per affrontare questo preciso problema.Quindi, se qualcuno risponde con una soluzione specifica per Postgres, usala con tutti i mezzi.

Un modo standard per effettuare una query ricorsiva in SQL sono ricorsivi CTE. PostgreSQL li supporta da allora 8.4.

Nelle versioni precedenti, puoi scrivere una funzione ricorsiva che restituisce set:

CREATE FUNCTION fn_hierarchy (parent INT)
RETURNS SETOF example
AS
$$
        SELECT  example
        FROM    example
        WHERE   id = $1
        UNION ALL
        SELECT  fn_hierarchy(id)
        FROM    example
        WHERE   parentid = $1
$$
LANGUAGE 'sql';

SELECT  *
FROM    fn_hierarchy(1)

Vedi questo articolo:

Se utilizzi SQL Server 2005, esiste un modo davvero interessante per farlo utilizzando le espressioni di tabella comuni.

Elimina tutta la fatica dalla creazione di una tabella temporanea e in pratica ti consente di fare tutto solo con WITH e UNION.

Ecco un buon tutorial:

http://searchwindevelopment.techtarget.com/tip/0,289483,sid8_gci1278207,00.html

usare un espressione di tabella comune.

Potrebbe voler indicare che si tratta solo di SQL Server 2005 o versione successiva. Dale Ragan

ecco un articolo sulla ricorsione da parte di SqlTeam senza espressioni di tabella comuni.

Il seguente codice viene compilato ed è testato correttamente.

create or replace function subtree (bigint)
returns setof example as $$
declare
    results record;
    entry   record;
    recs    record;
begin
    select into results * from example where parent = $1;
    if found then
        for entry in select child from example where parent = $1 and child  parent loop
            for recs in select * from subtree(entry.child) loop
                return next recs;
            end loop;
        end loop;
    end if;
    return next results;
end;
$$ language 'plpgsql';

La condizione "figlio <> genitore" è necessaria nel mio caso perché i nodi puntano a se stessi.

Divertiti :)

Oracle ha "INIZIA CON" e "COLLEGA DA"

select 
    lpad(' ',2*(level-1)) || to_char(child) s

from 
    test_connect_by 

start with parent is null
connect by prior child = parent;

http://www.adp-gmbh.ch/ora/sql/connect_by.html

Solo per una breve parentesi, sebbene alla domanda sia stata data una risposta molto buona, va notato che se consideriamo questo come un:

domanda SQL generica

quindi l'implementazione SQL è abbastanza semplice, poiché SQL'99 consente la ricorsione lineare nelle specifiche (anche se credo che nessun RDBMS implementi completamente lo standard) attraverso WITH RECURSIVE dichiarazione.Quindi da un punto di vista teorico possiamo farlo proprio ora.

Nessuno degli esempi ha funzionato bene per me, quindi l'ho risolto in questo modo:

declare
    results record;
    entry   record;
    recs    record;
begin
    for results in select * from project where pid = $1 loop
        return next results;
        for recs in select * from project_subtree(results.id) loop
            return next recs;
        end loop;
    end loop;
    return;
end;

è questo SQL Server?Non potresti scrivere una procedura memorizzata TSQL che esegua il loop e unisca i risultati insieme?

Sono anche interessato se esiste un modo solo SQL per farlo.Da quello che ricordo dal mio corso sui database geografici, dovrebbe esserci.

Penso che sia più semplice in SQL 2008 con ID gerarchia

Se hai bisogno di archiviare grafici arbitrari, non solo gerarchie, potresti mettere Postgres da parte e provare un database di grafici come AllegroGrafico:

Tutto nel database del grafico è archiviato come un triplo (nodo di origine, bordo, nodo di destinazione) e offre un supporto di prima classe per manipolare la struttura del grafico e interrogarla utilizzando un linguaggio simile a SQL.

Non si integra bene con qualcosa come Hibernate o Django ORM, ma se prendi sul serio le strutture dei grafici (non solo le gerarchie come ti offre il modello Nested Set), dai un'occhiata.

Credo anche che Oracle abbia finalmente aggiunto il supporto per i grafici reali nei suoi ultimi prodotti, ma sono stupito che ci sia voluto così tanto tempo e che molti problemi potrebbero trarre vantaggio da questo modello.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top