[ Shadowed @ 12.01.2008. 12:04 ] @
Naslov nije bas najbolji, ali nemam pojma kako bih preciznije naveo, ako neko ima predlog, menjam :)

Elem, o cemu se radi. Imam tabelu koja ima ID, neke podatke i krajnju kolonu ParentID koja sadrzi vrednost ID-a iz iste tabele (samo nekog drugog reda). Mislim da ce jasnije biti ako se pogleda slika. Levo je ono sto je predstavljeno podacima u bazi, desno je gore tabela a dole rezultat upita za recimo zadat broj 4. Ono sto mi je potrebno (ako je to ikako moguce) je da jednim upitom dobijem red sa trazenim ID-om, njegov parent, parent-ov parent i tako sve do root-a (kojem je ParentID null ili neka predvidjena vrednost). Mogao bih to uraditi tako sto pozovem prvo jedan upit da dobijem red pa onda jedan za parent-a i tako do root-a, ali bih vise voleo ako se to moze dobiti jednim upitom.
Nije u pitanju neka konkretna baza, jer ce mi trebati za vise njih (tako da bi navodjenje razlika u resenju za konkretne baze bilo pozeljno). Doduse, verovatno ce biti u pitanju najcesce MS SQL, zatim Access i MySql.
Evo i slike:
[att_img]

Hvala unapred :)
[ goranvuc @ 12.01.2008. 13:29 ] @
Ono sto odmah mogu da ti kazem je da Access zaboravis, a u MSSQL-u to lako mozes postici sa rekurzivnom funkcijom.
[ Shadowed @ 12.01.2008. 18:43 ] @
Hm, nisam bas siguran da znam i kako, gledao sam malo primere koje sam izguglao, ali nisam ukapirao. Najgore sto nisam u mogucnosti da probam. Moze primer?

A i nesto razmisljam da cu aplikaciju ograniciti ipak samo na MS SQL... i iz nekih drugih razloga...
[ goranvuc @ 12.01.2008. 19:12 ] @
Mislio sam na koriscenje UDF (User defined function) u MS SQL-u. Ja sam to koristio kada mi je trebala rekurzija u problematici sledivosti proizvodnje.

Druga varijanta koju sam koristio kada je stvar bila isuvise komplikovana za primenu je koristenje trigger-a za upis putanje (od top level parenta do konkretnog clana) u odgovarajuce polje (dakle mora se predvideti polje za putanju clana hijerarhije), sto mi je omogucilo vecu fleksibilnost u koristenju SQL-a za izvlacenje bilo kakvih setova: "daj svu decu koja su direktni ili indirektni potomci clana 5" i sl.

Inace, vec je bilo nesto na ovu temu, potrazicu pa ti javim.

Evo nadjoh nesto sto je skorije bilo http://www.elitesecurity.org/t253117
[ Shadowed @ 12.01.2008. 21:14 ] @
OK, ovo ce biti korisno. Ja se bas nadao da postoji neko resenje u cistom sql-u, nezavisno od RDBMS-a, ali nema veze. Na kraju krajeva, jos uvek ispitujem stvari, mozda ovo zaobidjem skroz :)

Zahvaljujem :)
[ jablan @ 12.01.2008. 21:41 ] @
Citat:
goranvuc: upis putanje (od top level parenta do konkretnog clana) u odgovarajuce polje (dakle mora se predvideti polje za putanju clana hijerarhije), sto mi je omogucilo vecu fleksibilnost u koristenju SQL-a za izvlacenje bilo kakvih setova: "daj svu decu koja su direktni ili indirektni potomci clana 5" i sl.

I ja obično primenjujem ovo rešenje, samo korišćenjem stored procedure (ili aplikativne logike) umesto trigera. Sve parente ili svu decu dobijaš prostim "LIKE" uslovom.

Ustvari, primenjivao ranije, pošto u Railsu to ima gotovo:

http://wiki.rubyonrails.org/rails/pages/ActsAsTree

:P
[ goranvuc @ 12.01.2008. 21:45 ] @
Trigere koristim za odrzavanje hijerarhije (prilikom premestanja nekog clana i vezivanje za nekog drugog parenta), a za manipulaciju naravno ne.
[ BigFoot @ 13.01.2008. 02:05 ] @
Ovo ti je klasičan problem zapisa strukture stabla u strukturu tipa tabele. Pored polja ParentID, koristi dodatno polje Level koje odredjuje nivo dubine stabla za svaki element i stvari će postati znatno jednostavnije.
[ dusans @ 13.01.2008. 11:40 ] @
Moze vrlo lako u bilo kom SQL-u ako smes da ogranicis broj nivoa (u praksi ces uvek imati nekav broj nivoa preko kog nema smisla ici, npr. suludo je da ce neko da rucno organizuje podatke na vise od 20-30 nivoa)

Primer za T-SQL i 5 nivoa (vise nivoa, veci upit):

Code:


SELECT Data.Name,
            Parent1.Name AS Parent1Name,
            Parent2.Name AS Parent2Name,
            Parent3.Name AS Parent3Name,
            Parent4.Name AS Parent4Name,
            Parent5.Name AS Parent5Name
FROM Data
LEFT OUTER JOIN Data AS Parent1 ON Data.ParentID = Parent1.ID
LEFT OUTER JOIN Data AS Parent2 ON Parent1.ParentID = Parent2.ID
LEFT OUTER JOIN Data AS Parent3 ON Parent2.ParentID = Parent3.ID
LEFT OUTER JOIN Data AS Parent4 ON Parent3.ParentID = Parent4.ID
LEFT OUTER JOIN Data AS Parent5 ON Parent4.ParentID = Parent5.ID



Pozdrav!
[ goranvuc @ 13.01.2008. 11:56 ] @
Njemu trebaju podaci kao redovi, a ne svi preci u jednom redu. Ali OK, moze posluziti za dobijanje putanje.
[ Shadowed @ 13.01.2008. 21:32 ] @
Moglo bi posluziti za nevolju, ali je goran u pravu kada kaze za redove, posto mi jedan red kasnije postaje jedan objekat u programu.
[ Sasa Popovic @ 14.01.2008. 08:13 ] @
Pozdrav svima,

Ako koristite SQL Server 2005 (ili Express Edition) onda je resenje koriscenje rekurzivnih upita uz upotrebu Common Table Expressions. Vise o ovome mozete procitati na: http://msdn2.microsoft.com/en-us/library/ms186243.aspx.

Napisao sam kratak primer koji demonstrira ono sto je trazeno u post-u:
Code:

declare @data table  (ID int not null, [Name] nvarchar(10) not null, ParentID int null)

insert into @data values (0, 'root', null)
insert into @data values (1, 'ch1', 0)
insert into @data values (2, 'ch2', 0)
insert into @data values (3, 'ch3', 0)
insert into @data values (4, 'ch1-1', 1)
insert into @data values (5, 'ch1-2', 1);

WITH SelectedData (ID, [Name], ParentID, Level)
AS
(
    SELECT ID, [Name], ParentID, 0 AS Level
    FROM @data
    WHERE ID = 4

    UNION ALL

    SELECT parent.ID, parent.[Name], parent.ParentID, Level + 1
    FROM  @data parent
        INNER JOIN SelectedData child on child.ParentID = parent.ID

)
SELECT ID, [Name], ParentID
FROM SelectedData
ORDER BY Level DESC


Pozdrav,
Sasa
[ hyle @ 14.01.2008. 08:28 ] @
Možda bi ti ovo bilo zanimljivo: The Nested Set Model
[ vilyu @ 14.01.2008. 09:17 ] @
Citat:
dusans: Moze vrlo lako u bilo kom SQL-u ako smes da ogranicis broj nivoa (u praksi ces uvek imati nekav broj nivoa preko kog nema smisla ici, npr. suludo je da ce neko da rucno organizuje podatke na vise od 20-30 nivoa)

Moram da primetim da je ovo resenje izuzetno neprakticno, usled velikog broja spajanja tabela koje ce trajati znatno duze nego vise pretrazivanja jedne tabele u slucaju rekurzivnog algoritma.
[ Shadowed @ 14.01.2008. 23:07 ] @
E, hvala ljudi, iskreno receno, nisam se ni nadao ovolikom odzivu :)
[ RAIN--SONG @ 21.01.2008. 16:58 ] @
Sada ne znam jesam dobro razumio pitanje, ali koliko kuzim trebas napraviti neku hijerarhiju. Netko je dao link na model ugnijezdjenoga skupa (nested sed model), a ja cu ovdje objasniti kako se stablo pravi pomocu popisa modela susjedstva (eng. . Adjacency list model). Tj. opisat cu samo kreiranje stabla pomocu popisa modela susjedstva. Imas ovo jako dobro objasnjeno u knjizi Joe Celko's Sql for Smarties, a ima i knjiga samo o stablima. Kako ovdje nije dopusten piratluk ne mogu je staviti. PM-aj za dodatne informacije o knjizi ako hoces.

Dakle imamo neko stablo recimo ovo http://en.wikipedia.org/wiki/Image:Binary_tree.svg


dijete otac
=============
'2' NULL
'7' '2'
'5' '2'
'2' '7'
'6' '7'
'5' '6'
'11' '6'
'9' '5'
'4' '9'

Opsirnije ovdje http://en.wikipedia.org/wiki/Adjacency_list

Ovo se moze napisat pomocu matrice susjedstva, ali meni se ne da tipkat. =)

Dakle pravljenje tablice

CREATE TABLE Stablo_susjedstva
(child CHAR(2) NOT NULL,
parent CHAR(2), -- null is korijen
PRIMARY KEY (child, parent));

Kod je iz gore navedene knjige ili mu ja barem slican =)

Ogranicenja su da ima samo jedan korijen.
CREATE TABLE
(child CHAR(2) NOT NULL,
parent CHAR(2), -- null is root
PRIMARY KEY (child, parent),
CONSTRAINT jedan_korijen
CHECK((SELECT COUNT(*)
FROM AdjTree
WHERE parent IS NULL) = 1)
...);

nema kruzenja etc...

Obilasci bi islo ovako:

SELECT P1.child, ' je roditelj ', C1.child
FROM Stablo_susjedstva AS P1, Stablo_susjedstva AS C1
WHERE P1.child = C1.parent;


etc... etc...

Uglavnom ona knjiga je ono sto ti treba ako nisam u krivu. =)








[ Fitopatolog @ 21.01.2008. 18:02 ] @
Ne čitate ostale teme na ovom forumu?

rešenje već imate u temi "Zadatak za ER SQL znalce". Treba koristiti rekurzivni SQL i opciju "WITH" u DB2 i MSSQL bazama i opciju "CONNECT BY" u Oraklu.
[ Sasa Popovic @ 21.01.2008. 18:29 ] @
@RAIN--SONG, ne bih se bas slozio da je resenje koje ste naveli ono sto je trazeno. Kako bi ste sa tim resenjem izvukli sve strukturu za child sa ID-jem 4? U svakom slucaju, resenje je koriscenje Common Table Expressions kao sto sam naveo ranije.

@Fitopatolog, ja nisam procitao tu temu do sada a sada kada sam je procitao ne bih rekao da smo mi ostali ovde pogresili time sto smo probali da pomognemo autoru pitanja. Ako nekome ko nije koristio Common Table Expressions (ili slicne metode) napisete da je resenje koriscenje Common Table Expressions i date mu link na neki primer koji nema veze sa onim sto on trazi onda u vecini slucajeva za onog ko je postavio pitanje odgovor nema mnogo smisla.
[ PavleBgd @ 26.01.2008. 18:02 ] @
Zasto ne probas sa kursorima da resis problem rekurzivnog ispisa strukture?

Code:

CREATE PROCEDURE [ReferenceTableTest] 
    @IDParent INT
AS

DECLARE @IDTempID INT

set nocount on
IF EXISTS (SELECT * FROM tempdb.dbo.sysobjects WHERE NAME = '##TestStruktura')    
DROP TABLE ##TestStruktura
CREATE TABLE [dbo].[##TestStruktura] (
    [IDChild] [int] NULL ,
    [Opis] [varchar] (50)  NULL ,
    [IDParent] [int] NULL
) ON [PRIMARY]

DELETE FROM ##TestStruktura
INSERT INTO ##TestStruktura
SELECT * FROM TestTabela
WHERE IDChild=@IDParent

DECLARE cur_lss CURSOR
FOR SELECT IDChild FROM ##TestStruktura
OPEN cur_lss
FETCH cur_lss INTO @IDTempID
WHILE (@@FETCH_STATUS <> -1)
BEGIN
    IF (@@FETCH_STATUS <> -2)
    BEGIN
        INSERT INTO ##TestStruktura
        SELECT * FROM TestTabela
        WHERE IDParent=@IDTempID
    END        
    FETCH cur_lss INTO @IDTempID
END
close cur_lss
DEALLOCATE cur_lss
set nocount off
select * from ##TestStruktura

DROP TABLE ##TestStruktura
GO


TestTabela treba da bude iste strukture kao tabela ##TestStruktura.
Output se generise dinamicki, nema ogranicenja po pitanju dubine strukture.
Iako sam na slican rekurzivno mogao da resim ovaj problem
ovo resenje mi se jos tada ucinilo jednostavnijim i elegantnijim
Pozdrav

[Ovu poruku je menjao PavleBgd dana 27.01.2008. u 08:41 GMT+1]
[ vokus @ 27.01.2008. 20:25 ] @
Ako Oracle dolazi u obzir onda vidi ovo:
http://www.psoug.org/reference/connectby.html