Re: lost on self joins

From: Tomasz Myrta <jasiek(at)klaster(dot)net>
To: Matthew Nuzum <cobalt(at)bearfruit(dot)org>
Cc: pgsql-sql(at)postgresql(dot)org
Subject: Re: lost on self joins
Date: 2003-01-15 19:59:43
Message-ID: 3E25BDAF.8060109@klaster.net
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-sql

Matthew Nuzum wrote:

>Sometimes recursion makes my head spin...
>
>Imagine that I have a database that holds the structure of my
>filesystem. There is a table called files that contains every piece of
>info you would ever want to know about a file, including a unique ID
>called fileid.
> | files
>========
>x| fileid
> | filename
> | ...
>
>Then, you have a table called folders which looks like:
> | folders
>==========
>x| folderid
> | parentid (relates to folders.folderid)
> | foldername
>
>Finaly, a table to allow a many to many join called files_folders
> | files_folders
>================
>x| ffid
> | folderid (fk to folders.folderid)
> | fileid (fk to files.fileid)

Strange. Do you need this table? Can one file exist in several directories?
If not, you can just add "folderid" field into table files.

>Now, I'd like to create a view that shows everything in files, as well
>as the complete path to the file. However because I don't know how many
>levels deep the file is nested, I'm not sure how to get that complete
>path. Here is conceptually what should come out:
>
> | files_view
>==============
>x| fileid
> | filename
> | ...
> | full_path
>
>Something that won't work is:
>SELECT files.*, folders.foldername, folders2.foldername
>FROM files, folders, folders folders2, files_folders ff
>WHERE files.fileid = ff.fileid
> AND ff.folderid = folders.folderid
> AND folders.parentid;
>
>The problem is that files that are not in a folder won't show up, and if
>a folder is more than two levels deep it will only show the two highest
>levels.
>
>Can anyone suggest a way for me to get the information I need? I'm very
>content to use a simple pl/pgsql function, however I don't know how I'd
>use recursion there.

What would you say about this:

create or replace function parent_dir(varchar,integer) returns varchar as '
DECLARE
curr_name ALIAS for $1;
curr_id ALIAS for $2;
par_name varchar;
par_id integer;
begin
select into par_name,par_id foldername,parentid from folders where folderid=curr_id;
if not found or par_name is null then
--finish
return curr_name;
else
--find upper folder
return parent_dir(par_name || ''/'' || curr_name,par_id);
end if;
end;
' LANGUAGE 'plpgsql';

Using:
select parent_dir('',folderid) as fullpath...;
or
select parent_dir(filename,folderid) as fullfilename...;

Your query would look like this:
SELECT files.*,
parent_dir('',folderid) as fullfoldername
FROM files f join files_folders ff using (fileid);

Regards,
Tomasz Myrta

In response to

Responses

Browse pgsql-sql by date

  From Date Subject
Next Message Achilleus Mantzios 2003-01-15 20:02:46 Re: index on to_char(created, 'YYYY') doesn't work
Previous Message Antti Haapala 2003-01-15 19:51:16 Re: RFC: A brief guide to nulls