On 2/17/06, SanjayK <[EMAIL PROTECTED]> wrote:
>
>
> Dennis,
>
> I understand what you are saying. My problem is specific to only the
> sorting. Given the tree:
>
> P1
>     C1
>        GC1
>     C2
>        GC2
>        GC3
>     C3
> P2
>     C4
>     C5
>        GC4
>     C6
> P3
>
> This structure is perfect for my use. In fact, this is the way I want it.
> The children at any level should immediately follow their parent in the
> table.
>
> Now suppose, each of these items had a field "Size" and I want to sort
> this
> table such that the structure remains same but the siblings are sorted by
> size. For example, the result of a sort might be:
>
> P1
>     C2
>        GC3
>        GC2
>     C3
>     C1
>        GC1
> ...
>
> Here, the position of the siblings changed according to sort but the
> structure didn't break. I want to know the SQL for achieving this sort
> using
> the path and the size. For example, if I were to use the path as you
> described and do an ORDER BY path, size, it will do this but the structure
> of the table will break. Because the paths of the siblings would be same
> and
> hence they will become clubbed together and won't be separated by their
> children as in the actual structure.
>
> If it is still unclear, I will make and post a real sample.
>
>
> Sanjay,

You can get close to the depth first order of the first list by ordering by
the full path to the nodes.

select * from tree order by path || id || '/';

This is correct for this sample

insert into tree (id, parent_id, data) values (NULL, NULL, 'P1');
insert into tree (id, parent_id, data) values (NULL, NULL, 'P2');
insert into tree (id, parent_id, data) values (NULL, NULL, 'P3');
insert into tree (id, parent_id, data) values (NULL, 1, 'C1');
insert into tree (id, parent_id, data) values (NULL, 1, 'C2');
insert into tree (id, parent_id, data) values (NULL, 1, 'C3');
insert into tree (id, parent_id, data) values (NULL, 2, 'C4');
insert into tree (id, parent_id, data) values (NULL, 2, 'C5');
insert into tree (id, parent_id, data) values (NULL, 2, 'C6');
insert into tree (id, parent_id, data) values (NULL, 4, 'GC1');
insert into tree (id, parent_id, data) values (NULL, 5, 'GC2');
insert into tree (id, parent_id, data) values (NULL, 5, 'GC3');
insert into tree (id, parent_id, data) values (NULL, 8, 'GC1');

Which displays as

sqlite> select * from tree order by (path || id || '/');
1                       P1          /
4           1           C1          /1/
10          4           GC1         /1/4/
5           1           C2          /1/
11          5           GC2         /1/5/
12          5           GC3         /1/5/
6           1           C3          /1/
2                       P2          /
7           2           C4          /2/
8           2           C5          /2/
13          8           GC1         /2/8/
9           2           C6          /2/
3                       P3          /

However, it will not always be correct because it uses a lexigraphic
ordering which isn't quite right.

If we change the query slightly to display the full path it is sorting on,
we see.

sqlite> select *, path || id || '/' as full from tree order by full;
1                       P1          /           /1/
4           1           C1          /1/         /1/4/
10          4           GC1         /1/4/       /1/4/10/
5           1           C2          /1/         /1/5/
11          5           GC2         /1/5/       /1/5/11/
12          5           GC3         /1/5/       /1/5/12/
6           1           C3          /1/         /1/6/
2                       P2          /           /2/
7           2           C4          /2/         /2/7/
8           2           C5          /2/         /2/8/
13          8           GC1         /2/8/       /2/8/13/
9           2           C6          /2/         /2/9/
3                       P3          /           /3/

Now if we arbitrarily change the id of C3 from 6 to 14 we will break the
lexigraphic ordering.

sqlite> update tree set id = 14 where id = 6;
sqlite> select *, path || id || '/' as full from tree order by full;
1                       P1          /           /1/
14          1           C3          /1/         /1/14/
4           1           C1          /1/         /1/4/
10          4           GC1         /1/4/       /1/4/10/
5           1           C2          /1/         /1/5/
11          5           GC2         /1/5/       /1/5/11/
12          5           GC3         /1/5/       /1/5/12/
2                       P2          /           /2/
7           2           C4          /2/         /2/7/
8           2           C5          /2/         /2/8/
13          8           GC1         /2/8/       /2/8/13/
9           2           C6          /2/         /2/9/
3                       P3          /           /3/

This is because the string /1/1 (the first part of /1/14) sorts before the
string /1/4. To solve this we need to create a custom collation function for
the path that understands that the path ids can't be broken up. This should
be possible using the sqlite3_create_collation API to create a tree_path
collation, and then ordering using that collation.

select * from tree order by path || id || '/' collate tree_path;

I am going to write such a collation function to go along with the
materialized path tree tables.

As for sorting by size, that will take some more thought. The full path
above is a complete ordering so it won' t do any good to also order by size.
I think it will be necessary to create a size_path field that is much like
the id path used for the tree. It would track the hierarchy of sizes. I
think this can be done in an auxiliary table joined to the tree.

I will let you know. I won' t get a chance to look at this for a few days as
I will be away from home (i.e. no PC).

HTH
Dennis Cote

Reply via email to