speedy: Kleine Textdatenbank basteln

Hallo Forumler,

ich bin in PERL noch ein ziemlicher Anfänger, deshalb brauche ich mal Euren Rat. Ich möchte in einer ASCII-Datei einige "Datensätze" speichern. Jeweils einige Schlüssel mit dazugehörigen Werten. Später sollen dann u.a. auch Daten wie z.B. "Welche verschiedenen Werte kommen im Feld XY vor" oder "wieviele Datensätze gibt es überhaupt". Meine Frage ist nun, wie man so eine "Textdatenbank" am besten aufbaut um sie dann später möglichst einfach auszulesen und auszuwerten.

Für Eure Hilfe besten Dank
speedy

  1. ich bin in PERL noch ein ziemlicher Anfänger,

    Ich denke, der wesentliche Teil Deines Problems ist unabhängig von der Programmiersprache.

    Ich möchte in einer ASCII-Datei einige "Datensätze" speichern.
    Jeweils einige Schlüssel mit dazugehörigen Werten.

    Dann fang mal damit an, diese Datensätze zu beschreiben und zu klassifizieren.

    Sind alle Daten vom selben Format? Oder hast Du mehrere Sorten von Daten?
    Welches Deiner Datenelemente wird durch welche Eigenschaften beschrieben?
    Falls letzteres: Welche Beziehungen bestehen zwischen diesen Daten? (So was in der Art: "Ein X-Ding hat mehrere Y-Dinger" ...).
    Wenn Du das hast, dann kannst Du die Menge der Tabellen und zu jeder von diesen die Menge der Spalten festlegen.
    (Das ist noch nicht alles, aber bei einfachen Fällen die Hauptsache.)

    Als nächstes kommt die Frage: "Wie realisiere ich eine Tabelle?"
    Im einfachsten Fall kannst Du pro Tabelle einfach eine Datei verwenden. Wenn Du sicherstellen kannst, daß ein bestimmtes Zeichen in keinem Deiner Feldinhalte vorkommt, dann kannst Du die Felder eines Datensatzes innerhalb einer Zeile durch dieses Zeichen getrennt darstellen; kannst Du das nicht, dann wird es aufwendiger.
    All dies findet noch lange vor der Verwendung einer Programmiersprache statt - es sei denn, Du willst einen vorgefertigten Datenbank-Zugangsmodul verwenden, wie Perl das anbietet.

    Später sollen dann u.a. auch Daten wie z.B. "Welche verschiedenen Werte kommen im Feld XY vor" oder "wieviele Datensätze gibt es überhaupt".

    Wenn Du eine entsprechende Darstellung einer Tabelle hast, kannst Du eine Schleife über alle Datensätze der Tabelle laufen lassen und Deine Abfragen relativ einfach realisieren.
    Mit einer richtigen relationalen (SQL-)Datenbank lassen sich Deine Anforderungen direkt in SQL formulieren.

    Meine Frage ist nun, wie man so eine "Textdatenbank" am besten aufbaut um sie dann später möglichst einfach auszulesen und auszuwerten.

    Wie gesagt: Die Grundlage ist es, die eigenen Daten zu verstehen und exakt zu beschreiben.

    1. Hallo Michael,

      erstmal vielen Dank für Deine ausführliche Antwort.
      Ich möchte das ganze eben in einer Textdatenbank realisieren, um auf die Daten auch mit primitvsten Mitteln zugreifen zu können. Meine Struktur sieht im Moment folgendermassen aus:

      *XY*Datendaten
      *END* #Der Datensatz ist zuende

      *XY*NächsteDaten
      *END*

      wobei zwischen den Sternen der Feldname bezeichnet wird und hinter dem zweiten Stern immer die Daten in der Zeile stehn. Da ich mir mit deinem ersten Posting meine strukturellen Fragen wahrscheinlich selbst beantworten kann, hab ich aber noch eine Frage: Wie muss ich ungefähr vorgehen, wenn ich aus so einer Struktur die bereits erwähnte Abfrage "Welche verschiedenen Werte gibt es im Feld XY" basteln möchte? Ich will jetzt keinen Code haben sondern nur einen Wegweiser so ca. wie im ersten Posting. Kann mir jemand helfen?

      Dankschön
      speedy

      1. *XY*Datendaten
        *END* #Der Datensatz ist zuende

        Wenn Deine Daten (ist das nur ein Feld, oder mehrere?) keinen "*" enthalten, dann scheint das zu funktionieren. Aber die Trennung zwischen den Datensätzen brauchst Du nicht - Du hast ja die Trennung der Zeilen (1 Datensatz pro Zeile, wenn Deine Daten kein "\n" enthalten - und deshalb würde ich dann ggf. auch gleich "\n" als Separator zwischen den Spalten nehmen).

        Wie muss ich ungefähr vorgehen, wenn ich aus so einer Struktur die bereits erwähnte Abfrage "Welche verschiedenen Werte gibt es im Feld XY" basteln möchte?

        Einen Hash anlegen, über alle Werte des Feldes laufen, jeweils den Feldwert als Hash-Schlüssel verwenden und einen beliebigen Wert in den Hash hineinschreiben (Duplikate sind egal, einfach drüberschreiben).
        Am Ende beschreiben die keys(%hash) genau die Menge aller vorliegenden Werte.

        Wenn der Wert, den Du hineinschreibst, ein Inkrement (++) des vorherigen Wertes ist, dann zählst Du sogar nebenbei mit, wie oft jeder Wert vorkommt.
        Erfreulicherweise setzt ein "++" auf einen vorher undefinierten Wert eine "1" hinein - Du brauchst also keine Fallunterscheidung zwischen neuen und bereits gefundenen Werten.

        1. Die Daten können schon einen * enthalten. Suche mit einer Mustererkennung nach \(..)\ (ich hoff, das ist so ungefähr richtig - Anfänger halt) da der Feldname immer nur zwei Zeichen lang ist. Ein Datensatz kann allerdings mehere Felder enthalten:

          *AB*Mein erstes Feld
          *XY*Mein zweites Feld
          *END*

          Deshalb brauche ich auch das *END*, damit mein Script weis, wann es wieder einen neuen Datensatz ausliest.

          Einen Hash anlegen...

          Ich weis jetzt zwar nicht, ob ich das so verstanden habe, wie Du‚s gemeint hast, aber ich hab jetzt ne Ahnung, wie ich‚s machen könnte.
          Aber bis ich die Abfrage programmiere wird noch etwas Zeit vergehen.

          Kennst Du eigentlich irgendwelche (möglichst deutschsprachige) Adressen, bei denen man sich als PERL-Einsteiger Ideen/Rat holen kann?

          CU
          speedy

          1. Ein Datensatz kann allerdings mehere Felder enthalten:
            *AB*Mein erstes Feld
            *XY*Mein zweites Feld
            *END*

            Entscheidend ist nicht, ob es mehrere Felder sind, sondern ob es variabel viele sind.

            Deshalb brauche ich auch das *END*, damit mein Script weis, wann es wieder einen neuen Datensatz ausliest.

            Wenn Du weißt, daß es immer zwei Felder sind, brauchst Du den nicht.

            Kennst Du eigentlich irgendwelche (möglichst deutschsprachige) Adressen, bei denen man sich als PERL-Einsteiger Ideen/Rat holen kann?

            Abgesehen von diesem Forum hier? ;-)
            Da gäbe es auch noch http://www.teamone.de/selfaktuell/links/cgi_perl_.htm ... hilft das?

            1. Entscheidend ist nicht, ob es mehrere Felder sind, sondern ob es variabel viele sind.
              Wenn Du weißt, daß es immer zwei Felder sind, brauchst Du den nicht.

              In der einen Datenbankdatei könnten es drei, in der nächsten fünf oder auch nur eines sein. Aber für jede Datenbank immer den selben Feldsatz pro Eintrag.

              Abgesehen von diesem Forum hier? ;-)
              Da gäbe es auch noch http://www.teamone.de/selfaktuell/links/cgi_perl_.htm ... hilft das?

              Scherzkeks! Ich meinte irgendwelche anderen Quellen außer perl.com usw.

              CU
              speedy

              1. Hallo speedy,

                Ich hoffe ich störe nicht ;-) Vor einiger Zeit hab` ich mich auch mit einer größeren Textdatenbank unter Perl beschäftigt. Innerhalb der Tabelle(Datei) habe ich die Datensätze in je eine Zeile geschrieben, und die Felder durch Sonderzeichen getrennt (Comma Separated Values).
                Da Du ja weist, wieviele Felder ein Datensatz in einer Tabelle hat, kannst Du ja anhand der Reihenfolge der Felder feststellen, um welches Attribut es sich handelt.
                In einer weiterentwickelten Form dieser CSV-Datenbank habe ich die Attributbezeichner in die erste Zeile geschrieben und ebenfalls durch Sonderzeichen getrennt. So konnte ich durch auslesen der ersten Zeile die Werte immer ihrem Attribut zuordnen. Um an die Daten zu kommen habe ich das ganze in eine Struktur vom Typ:

                $db{$tabelle}->{$primarykey}->{$attribut} = $value;

                eingelesen, wobei eines der Attribute als Primärschlüssel definiert wird, der für jeden Datensatz einmalig ist.
                So kannst Du jeden Datensatz einer bestimmten Tabelle über dessen Primärschlüssel ansprechen, bzw. auch durch Schleifen über die Keys der Hashs nach bestimmten Werten eines Attributs suchen.

                Hoffentlich kannst Du damit was Anfangen :-). Sollte nur als weiter Anregung zum Aufbau einer Textdatenbank dienen.

                Gruß AlexBausW

                P.S.: Unter der angegebenen URL wird eine (mehrere) CSV-Datei(en) verwendet.

                1. Hallo,

                  Ich hoffe ich störe nicht ;-) Vor einiger Zeit hab` ich mich auch mit einer größeren Textdatenbank unter Perl beschäftigt. Innerhalb der Tabelle(Datei) habe ich die Datensätze in je eine Zeile geschrieben, und die Felder durch Sonderzeichen getrennt (Comma Separated Values).
                  Da Du ja weist, wieviele Felder ein Datensatz in einer Tabelle hat, kannst Du ja anhand der Reihenfolge der Felder feststellen, um welches Attribut es sich handelt.
                  In einer weiterentwickelten Form dieser CSV-Datenbank habe ich die Attributbezeichner in die erste Zeile geschrieben und ebenfalls durch Sonderzeichen getrennt. So konnte ich durch auslesen der ersten Zeile die Werte immer ihrem Attribut zuordnen. Um an die Daten zu kommen habe ich das ganze in eine Struktur vom Typ:

                  $db{$tabelle}->{$primarykey}->{$attribut} = $value;

                  eingelesen, wobei eines der Attribute als Primärschlüssel definiert wird, der für jeden Datensatz einmalig ist.
                  So kannst Du jeden Datensatz einer bestimmten Tabelle über dessen Primärschlüssel ansprechen, bzw. auch durch Schleifen über die Keys der Hashs nach bestimmten Werten eines Attributs suchen.

                  Einen Schritt geschickter wird es dann, wenn man nun noch das Datenbank-Modul DBI einsetzt - und dazu den Datenbanktreiber (DBD) für CSV-Dateien -> DBD::CSV.

                  Normalerweise wird auch hier aus den CSV-Dateien die 1. Zeile für die Attribut-Namen verwendet. (geht aber auch anders). Dann kann man die Dateien wie eine Datenbank öffnen und mit SQL-Anfrage auf die Datensätze zugreifen:

                  'SELECT * FROM personen WHERE id > 17'

                  Macht einen fit für Datenbank-Anwendungen ;-) Und bei größeren Sachen kann man sich gleich auf mySQL stürzen ...

                  Jörk

                  1. Einen Schritt geschickter wird es dann, wenn man nun noch das Datenbank-Modul DBI einsetzt - und dazu den Datenbanktreiber (DBD) für CSV-Dateien -> DBD::CSV.
                    Normalerweise wird auch hier aus den CSV-Dateien die 1. Zeile für die Attribut-Namen verwendet. (geht aber auch anders). Dann kann man die Dateien wie eine Datenbank öffnen und mit SQL-Anfrage auf die Datensätze zugreifen:
                    'SELECT * FROM personen WHERE id > 17'

                    Kann der auch "group by", was für die vorliegende Aufgabenstellung dann die passende Idee wäre?

                    1. Einen Schritt geschickter wird es dann, wenn man nun noch das Datenbank-Modul DBI einsetzt - und dazu den Datenbanktreiber (DBD) für CSV-Dateien -> DBD::CSV.
                      Normalerweise wird auch hier aus den CSV-Dateien die 1. Zeile für die Attribut-Namen verwendet. (geht aber auch anders). Dann kann man die Dateien wie eine Datenbank öffnen und mit SQL-Anfrage auf die Datensätze zugreifen:
                      'SELECT * FROM personen WHERE id > 17'

                      Kann der auch "group by", was für die vorliegende Aufgabenstellung dann die passende Idee wäre?

                      Sollte eigentlich alles funktionieren. Das CSV-Modul habe ich bislang nur gelegentlich eigesetzt, daß ich jetzt gar nicht sicher sagen kann, schon mal mit 'group by' gearbeitet zu haben. 'order by' funktioniert aber auf alle Fälle - einer der Gründe, weshalb ich das Datenbankmodul für die CSV Datei eingesetzt habe ...

                      Jörk

                      1. Hi Jörk,

                        Kann der auch "group by", was für die vorliegende Aufgabenstellung dann die passende Idee wäre?

                        Sollte eigentlich alles funktionieren. Das CSV-Modul habe ich bislang nur gelegentlich eigesetzt, daß ich jetzt gar nicht sicher sagen kann, schon mal mit 'group by' gearbeitet zu haben. 'order by' funktioniert aber auf alle Fälle - einer der Gründe, weshalb ich das Datenbankmodul für die CSV Datei eingesetzt habe ...

                        Und wie sieht es mit Volltextsuche innerhalb eines Feldes aus ?

                        Gruß AlexBausW

                        1. Hallo Alex!

                          Kann der auch "group by", was für die vorliegende Aufgabenstellung dann die passende Idee wäre?

                          Sollte eigentlich alles funktionieren. Das CSV-Modul habe ich bislang nur gelegentlich eigesetzt, daß ich jetzt gar nicht sicher sagen kann, schon mal mit 'group by' gearbeitet zu haben. 'order by' funktioniert aber auf alle Fälle - einer der Gründe, weshalb ich das Datenbankmodul für die CSV Datei eingesetzt habe ...

                          Mit dem 'group by' muss ich leider Tom recht geben.

                          Und wie sieht es mit Volltextsuche innerhalb eines Feldes aus ?

                          Dafür kannst Du mit LIKE arbeiten. Das ist implementiert ...

                          Gruß,
                             Jörk

                    2. Hallo zusammen

                      Kann der auch "group by", was für die vorliegende Aufgabenstellung dann die passende Idee wäre?

                      Nein, der DBD-CSV-Treiber unterstützt keine Group-By-Klausel.
                      Der DBD-CSV-Treiber verwendet übrigens zur Interpretation von SQL-Statements das Modul SQL::Statement.
                      Zum Select-Statement findet man in der Man-Page folgende Erläuterung:

                      <cite source="Manpage zu SQL::Statement">

                      SELECT:

                      SELECT [DISTINCT] $col1, ... $colN FROM $table
                              [ WHERE $where_clause ] [ ORDER BY $ocol1, ... $ocolM ]

                      The $where_clause is based on boolean expressions of the form $val1 $op $val2, with $op being one of '=', '<>', '>', '<', '>=', '<=', 'LIKE', 'CLIKE' or IS. You may use OR,
                      AND and brackets to combine such boolean expressions or NOT to negate them.

                      </cite>

                      Die Gruppierungs-Funktion muss man also selber lösen, z.B. über das Verarbeiten von 2-dimensionalen Arrays.

                      Grüsse
                      Tom