aboutsummaryrefslogtreecommitdiff
path: root/challenge-146/luca-ferrari/postgresql/ch-2.sql
blob: 39d2cd1aac48526b9c57f7e6056f8e424427ef25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
DROP TABLE IF EXISTS fraction_tree;
CREATE TABLE fraction_tree (
       pk int GENERATED ALWAYS AS IDENTITY
       , numerator int default 1
       , denominator int default 1
       , child_of int
       , level int default 1
       , PRIMARY KEY( pk )
       , FOREIGN KEY (child_of) REFERENCES fraction_tree( pk )
);


TRUNCATE TABLE fraction_tree;
ALTER TABLE fraction_tree ALTER COLUMN pk RESTART;


INSERT INTO fraction_tree( numerator, denominator )
VALUES( 1, 1 );





CREATE OR REPLACE FUNCTION
f_add_one_level_fraction_tree()
RETURNS INT
AS $CODE$
DECLARE
        current_left   fraction_tree%rowtype;
        current_right  fraction_tree%rowtype;
        previous_tuple fraction_tree%rowtype;
        nodes_added    int := 0;
BEGIN

        FOR previous_tuple IN SELECT * FROM fraction_tree
                                     WHERE level = ( SELECT max( level ) FROM fraction_tree )
                                     LOOP


                current_left.numerator   := previous_tuple.numerator;
                current_left.denominator := ( previous_tuple.numerator + previous_tuple.denominator );
                current_left.child_of    := previous_tuple.pk;
                current_left.level       := previous_tuple.level + 1;
                current_left.pk          := nextval( 'fraction_tree_pk_seq' );

                current_right.numerator   := ( previous_tuple.numerator + previous_tuple.denominator );
                current_right.denominator := previous_tuple.denominator;
                current_right.child_of    := previous_tuple.pk;
                current_right.level       := previous_tuple.level + 1;
                current_right.pk          := nextval( 'fraction_tree_pk_seq' );

                INSERT INTO fraction_tree
                OVERRIDING SYSTEM VALUE
                SELECT current_left.*;

                INSERT INTO fraction_tree
                OVERRIDING SYSTEM VALUE
                SELECT current_right.*;

                nodes_added := nodes_added + 2;

       END LOOP;

       RETURN nodes_added;
END
$CODE$
LANGUAGE plpgsql;



CREATE OR REPLACE FUNCTION
f_populate_fraction_tree( levels int default 4 )
RETURNS int
AS $CODE$
DECLARE
        i           int := 0;
        nodes_added int := 0;
BEGIN
     FOR i IN 1 .. levels LOOP
         nodes_added := nodes_added + f_add_one_level_fraction_tree();
     END LOOP;

     RETURN nodes_added;
END
$CODE$
LANGUAGE plpgsql;


/*
testdb=> select * from  f_search_for_fraction_tree( 3, 5 );
description | fraction
-------------+----------
child       | 3/5
parent      | 3/2
grandparent | 1/2

*/

CREATE OR REPLACE FUNCTION
f_search_for_fraction_tree( numer int, denomin int )
RETURNS TABLE ( description text, fraction text )
AS $CODE$
DECLARE
        current_tuple fraction_tree%rowtype;
BEGIN
        SELECT 'child', numerator || '/' || denominator
        INTO description, fraction
        FROM fraction_tree
        WHERE numerator   = numer
        AND   denominator = denomin;

        IF FOUND THEN
           RETURN NEXT;


           SELECT 'parent', numerator || '/' || denominator
           INTO description, fraction
           FROM fraction_tree
           WHERE pk = ( SELECT child_of
                        FROM fraction_tree
                        WHERE numerator   = numer
                        AND   denominator = denomin );

           RETURN NEXT;



           SELECT 'grandparent', numerator || '/' || denominator
           INTO description, fraction
           FROM fraction_tree
           WHERE pk = ( SELECT child_of
                        FROM fraction_tree
                        WHERE pk = ( SELECT child_of
                                     FROM fraction_tree
                                     WHERE numerator   = numer
                                     AND   denominator = denomin ) );

          RETURN NEXT;

        END IF;

        RETURN;
END
$CODE$
LANGUAGE plpgsql;