Este posibil să se facă o interogare SQL recursiv?

voturi
62

Am un tabel similar cu acest lucru:

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

Eu pot utiliza câmpul parentid pentru a aranja datele într-o structură arborescentă.

Acum, aici e bit nu pot lucra. Având în vedere o parentid, este posibil să se scrie o instrucțiune SQL pentru a adăuga la toate domeniile de valoare sub care parentid și recursiv pe ramura de copac?

UPDATE: Sunt folosind PosgreSQL astfel încât fantezie caracteristici MS-SQL nu sunt disponibile pentru mine. În orice caz, aș vrea ca acest lucru să fie tratată ca o întrebare SQL generic.

BTW, eu sunt foarte impresionat de a avea 6 răspunsuri în termen de 15 minute de la pune întrebarea! Du-te overflow stivă!

Întrebat 09/09/2008 la 22:08
sursa de către utilizator
În alte limbi...                            


14 răspunsuri

voturi
0

este acest SQL Server? Nu s-a putut să scrie o procedură stocată TSQL care se arcuieste prin și sindicatele rezultatele împreună?

Sunt, de asemenea, interesat în cazul în care există o modalitate numai SQL de a face acest lucru, deși. Din biții mi amintesc din clasa mea bazele de date geografice, ar trebui să existe.

Publicat 09/09/2008 la 22:16
sursa de către utilizator

voturi
5

utilizați o expresie comună tabel .

Ar putea dori să indice acest lucru este SQL Server 2005 sau mai sus numai. Dale Ragan

aici este un articol de pe recursiune de SqlTeam fără expresii comune de masă.

Publicat 09/09/2008 la 22:17
sursa de către utilizator

voturi
0

Cred că este mai ușor în SQL 2008 cu HierarchyID

Publicat 09/09/2008 la 22:23
sursa de către utilizator

voturi
5

Dacă folosind SQL Server 2005, există o modalitate foarte misto de a face acest lucru folosind expresii comune de masă.

Este nevoie de toate gruntwork de a crea un tabel temporar, și basicly vă permite să faci totul cu doar un pandant cu UNION.

Aici este un tutorial bun:

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

Publicat 09/09/2008 la 22:23
sursa de către utilizator

voturi
1

Oracle are „START CU“ și „CONNECT“

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

Publicat 09/09/2008 la 22:30
sursa de către utilizator

voturi
15

Dacă doriți o soluție portabil , care va funcționa pe orice ANSI SQL-92 RDBMS, va trebui să adăugați o nouă coloană în tabel.

Joe Celko este autorul original al imbricate Seturi de abordare pentru a stoca ierarhii în SQL. Puteți Google „seturi imbricate“ ierarhie pentru a înțelege mai multe despre fundal.

Sau puteți redenumi doar parentid la leftid și adăugați un rightid .

Aici este încercarea mea de a rezuma seturi imbricate, care va cădea teribil de scurt, pentru că eu nu sunt Joe Celko: SQL este un limbaj bazat pe set, iar modelul de adiacenta (stocarea ID-mamă) nu este o reprezentare bazată pe set de o ierarhie. Prin urmare, nu există nici o metodă pură bazată pe set pentru a interoga o schemă adiacență.

Cu toate acestea , cele mai multe dintre platforme majore au introdus extensii în ultimii ani , pentru a face față cu această problemă precisă. Deci , dacă cineva răspunde cu o soluție Postgres-specifică, utilizați că , prin toate mijloacele.

Publicat 09/09/2008 la 22:40
sursa de către utilizator

voturi
-1

Dacă aveți nevoie pentru a stoca grafice arbitrare, nu doar ierarhii, ai putea împinge Postgres în lateral și să încerce o bază de date grafic , cum ar fi AllegroGraph :

Totul în baza de date a graficului este stocat ca un triplu (nod sursă, margine, nodul țintă) și vă oferă suport de primă clasă pentru manipularea structurii graficului și interogarea-l folosind un limbaj SQL.

Ea nu se integrează bine cu ceva de genul Hibernate sau Django ORM, dar dacă sunt serioase despre structuri grafic (nu doar ierarhiile ca modelul Nested Set vă oferă) verifica.

De asemenea, cred că Oracle a adăugat în cele din urmă un suport real grafice în cele mai noi produse, dar eu sunt uimit că a durat atât de mult, o mulțime de probleme ar putea beneficia de acest model.

Publicat 09/09/2008 la 23:30
sursa de către utilizator

voturi
11

Există câteva modalități de a face ceea ce aveți nevoie în PostgreSQL.

Ceva de genul:

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);
Publicat 10/09/2008 la 14:16
sursa de către utilizator

voturi
2

Codul de mai jos compilează și este testat pe OK.

creați sau să înlocuiască funcția subramificație (bigint)
se întoarce setof exemplu ca $$
declara
    înregistrarea rezultatelor;
    înregistrare de intrare;
    înregistrare recs;
ÎNCEPE
    selectați în rezultate * de exemplu, în cazul în care părinte = $ 1;
    dacă este găsit atunci
        pentru intrarea în selectați copil de exemplu, în cazul în care părinte = $ 1 și bucla părinte copil
            pentru recs în * selectați din subarborele (entry.child) buclă
                reapara recs;
            se încheie buclă;
        se încheie buclă;
    în cazul în care se încheie;
    întoarce rezultate pentru următoarele;
Sfârşit;
$$ limba 'plpgsql';

Condiția „copil <> părinte“ este necesară în cazul meu, deoarece nodurile indică spre ele însele.

A se distra :)

Publicat 03/02/2009 la 20:14
sursa de către utilizator

voturi
34

Începând cu versiunea 8.4, PostgreSQL are suport de interogare recursiv pentru expresiile de tabelă obișnuite folosind standardul SQL WITHsintaxa.

Publicat 14/02/2009 la 05:39
sursa de către utilizator

voturi
1

La fel ca și o scurtă parte, deși sa răspuns foarte bine, trebuie remarcat faptul că, dacă vom trata acest lucru ca:

generic SQL întrebare

apoi punerea în aplicare SQL este destul de drept înainte, ca SQL'99 permite recursie liniare în caietul de sarcini (deși cred că nu RDBMS pune în aplicare standardul complet) prin WITH RECURSIVEdeclarația. Deci , dintr - o perspectivă teoretică putem face acest lucru chiar acum.

Publicat 17/03/2009 la 21:38
sursa de către utilizator

voturi
1

Nici unul dintre exemplele lucrat OK pentru mine, așa că am fixat așa:

declara
    înregistrarea rezultatelor;
    înregistrare de intrare;
    înregistrare recs;
ÎNCEPE
    pentru rezultate în * selectați din proiect în cazul în care pid = $ de 1 buclă
        întoarce rezultate pentru următoarele;
        pentru recs în * selectați din project_subtree (results.id) buclă
            reapara recs;
        se încheie buclă;
    se încheie buclă;
    întoarcere;
Sfârşit;
Publicat 11/01/2011 la 15:03
sursa de către utilizator

voturi
10

O modalitate standard de a face o interogare recursiv SQLsunt recursive CTE. PostgreSQLle sprijină , deoarece 8.4.

In versiunile anterioare, puteți scrie o funcție revenind set recursiv:

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)

A se vedea acest articol:

Publicat 11/01/2011 la 15:11
sursa de către utilizator

voturi
42

Aici este un exemplu de script folosind expresia obișnuită de tabelă:

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

Script - ul de mai sus creează un tabel de „virtuale“ numit sumthiscare are coloane idși val. Acesta este definit ca rezultatul a două fuzionat cu selecteazã union all.

În primul rând selectdevine rădăcină ( where id = :selectedid).

În al doilea rând selecturmează copiii din rezultatele anterioare iterativ , până când nu este nimic să se întoarcă.

Rezultatul final poate fi apoi procesat ca un tabel normal. În acest caz, coloana val este rezumată.

Publicat 18/04/2011 la 08:50
sursa de către utilizator

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more