Datenbanken und Prolog
Tabellen in Prolog
Wir betrachten die folgenden beiden Tabellen:Tablle "t":
Tablle "s":
a b c 1 2 3 4 5 6 Die Tabellen kann man in Prolog folgendermaßen repräsentieren:
c d 3 7 6 8 t(1, 2, 3). t(4, 5, 6). s(3, 7). s(6, 8).Einfache Projektion
Folgende Regel selektiert die b-Spalte der Tabelle "t":Um mittels der Attributnamen selektieren zu können muß man auch die Tabellenstrukturen in Prolog repräsentieren:select_value_from_t(Value) :- t(_, Value, _). ?- select_from_t(Value). Value = 2 ; Value = 5 Yes select_all_values_from_t(Values) :- findall( Value, select_value_from_t(Value), Values ). ?- select_all_values_from_t(Values). Values = [2, 5] YesDann kann man etwas allgemeiner selektieren:attribute(t, 1, a). attribute(t, 2, b). attribute(t, 3, c). attribute(s, 1, c). attribute(s, 2, d).Man beachte, daß für jede Tabelle eine eigenes Prädikat select_value_from_Tabelle erforderlich ist.select_value_from_t(Attribute, Value) :- attribute(Table, N, Attribute), t(X, Y, Z), nth(N, [X, Y, Z], Value). ?- select_value_from_table(t, a, Value). Value = 1 ; Value = 4 YesAllgemeine Projektion
Wenn man allgemeine Tabellen generisch bearbeiten möchte, so kann man wie folgt vorgehen. Wir ändern die Repräsentation der Tabellen etwas:Da man nicht einfach "Table(Tuple)" aufrufen kann, wird zuerst mittels Goal =.. [Table, Tuple] ein neues Atom "Table(Tuple)" konstruiert und der Variablen Goal zugewiesen. Dieses wird dann mittels "call(Goal)" aufgerufen.t([1, 2, 3]). t([4, 5, 6]). s([3, 7]). s([6, 8]).Folgende Regel selektiert Paare aus Attributen und Werten:select_value_from_table(Table, Attribute, Value) :- attribute(Table, N, Attribute), Goal =.. [Table, Tuple], call(Goal), nth(N, Tuple, Value). select_all_values_from_table(Table, Attribute, Values) :- findall( Value, select_value_from_table(Table, Attribute, Value), Values ). ?- select_all_values_from_table(t, a, Values). Values = [1, 4] Yesselect_all_values_from_table(Table, AVs) :- findall( Attribute:Value, select_value_from_table(Table, Attribute, Value), Values ). ?- select_all_values_from_table(t, AVs). AVs = [a:1, b:2, c:3, a:4, b:5, c:6] YesSelektion
Die Selektion aller Tupel aus einer Tabelle, die einen speziellen Attributwert haben, kann wie folgt erfolgen:Das Ergebnis ist in diesem Falles eine Liste [[1, 2, 3]], die genau ein Tupel [1, 2, 3] enthält.select_tuple_with_value(Table, Attribute, Value, Tuple) :- attribute(Table, N, Attribute), Goal =.. [Table, Tuple], call(Goal), nth(N, Xs, Value). select_all_tuples_with_value(Table, Attribute, Value, Tuples) :- findall( Tuple, select_tuple_with_value(Table, Attribute, Value, Tuple), Tuples ). ?- select_all_tuples_with_value(t, a, 1, Tuples). Tuples = [[1, 2, 3]] YesAggregation
Die Summe aller Werte zu einem gegebenen Attribut kann wie folgt berechnet werden:sum_of_values(Table, Attribute, Sum) :- findall( Value, select_value_from_table(Table, Attribute, Value), Values ), add(Values, Sum). ?- sum_of_values(s, d, Sum). Sum = 15 YesJoin
Der Join aus "s" und "t" über gleiche Attributwerte für "c" kann wie folgt berechnet werden:join_of_s_and_t(Tuples) :- findall( [A,B,C,D], ( t(A,B,C), s(C,D) ), Tuples ). ?- join_of_s_and_t(Tuples). Tuples = [[1, 2, 3, 7], [4, 5, 6, 8]] YesIntergritätsbedingungen
Um zu testen, ob ein Attributname nur für eine einzige Spalte einer Tabelle benutzt, wird schreiben wir folgende Regel:Falls in der Definition der Tabellenstrukturen fäschlicherweise zwei Spalten mit demselben Attribut überschrieben wurden, etwadatabase_error(duplicate_attribute(Table, Attribute, [N1, N2])) :- attribute(Table, N1, Attribute), attribute(Table, N2, Attribute), N1 \= N2.so könnte das erkannt werden:attribute(t, 1, b). attribute(t, 2, b). attribute(t, 3, c). ...?- database_error(Message). Message = duplicate_attribute(t, b, [1, 2]) YesField Notation
Die folgende Repräsentation macht die explizite Repräsentation der Tabellenstrukturen mittels des Prädikats attribute überflüssig:Diese Repräsentation entspricht ziehmlich genau der XML-Repräsentation:t([a:1, b:2, c:3]). t([a:4, b:5, c:6]). s([c:3, d:7]). s([c:6, d:8]).Jetzt kann man wie folgt die Projektion auf ein Attribut berechnen:<table name="t"> <row a="1" b="2" c="3"/> <row a="4" b="5" c="6"/> </table> <table name="s"> <row c="3" d="7"/> <row c="6" d="8"/> </table>Mittels metalinguistischer Abstraktion könnte man diese Regel noch vereinfachen:select_all_values_from_table(Table, Attribute, Values) :- findall( Value, ( Goal =.. [Table, Tuple], call(Goal), member(Attribute:Value, Tuple) ), Values ).Hier ist := ein Prädikatensymbol in Infix-Notation, welches auf die beiden Argumente Value und Table^Attribute angewendet wird. Das zweite Argument Table^Attribute ist dabei ein Term mit dem Infix-Funktionssymbol ^.Value := Table^Attribute :- Goal =.. [Table, Tuple], call(Goal), member(Attribute:Value, Tuple). select_all_values_from_table(Table, Attribute, Values) :- findall( Value, Value := Table^Attribute, Values ).