Verena: MySQL: Anlegen eines Set-Datentyps mit vielen Werten funzt nicht

Hallo Forum,

ich habe folgendes Problem:
Ich habe in einer Tabelle eine Spalte mit dem DAtentyp Set. Die will ich nun mit folgendem Code generieren:

  
ALTER TABLE `database` CHANGE `categories` `categories` SET( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10' ) DEFAULT NULL  
  

Das klappt auch. Doch wenn ich statt 10 Werten 10.000 oder auch nur 100 nehme klappt es nicht (Nach dem MySQL-Manual können es eigentlich bis über 65.000 Werte sein!). Als Fehlermeldung gibt MySQL

Error: 1097 - Too many strings for column categories and SET  

an.

Da ich keine andere Methode gefunden habe wie man zum Beispiel immer nur einzelne Werte/Wertgruppen hinzufügt weiß ich nicht mehr weiter.

Ich habe es auch schon auf allen möglichen Wegen probiert (phpMyAdmin, MySQL-Front und MySQLManager). Wirft aber überall die selbe Fehlermeldung aus sobald ich eine größere Anzahl von Werten nehme.

Ich arbeite auf Win2000 + Apache 2.39 + MySQL 3.23.53

Wäre für Tipps sehr sehr dankbar.

Beste Grüße - Verena

PS: Wenn wer allgemein vielleicht auch noch ne gute Seite zum Thema Set-Datentyp weiß wäre das auch hilfreich.

  1. Hallo Verena,

    Da musst Du was falsch verstanden haben. Oder Dein Manual ist genauso falsch, wei mein Buch. Ich hab mel reingeschaut ins MySQL und festgestellt:

    Der SubType enum wird durch ein bis zwei Byte (ein oder zwei wäre richtiger) dargestellt und kann daher 65535 verschiedene Werte repräsentieren. = entspricht intern dabei "nicht gesetzt" also NULL. Es handelt sich um einen Index in die interne Liste.

    Der SubType set wird durch ein bis scht Byte repräsentiert und kann dadurch 8 bis 64 unterschiedliche Werte repräsentieren. Auch hier entspricht 0 natürlich "nicht gesetzt", aber es handelt sich ja um ein Flagregister. Jedem Bit steht ein Wert gegenüber.

    Wenn Du also multiple-Choice-Listen benötigst, dann wirst Du nicht um eine echte Normalisierung der Tabelle (also Abspaltung der Eigenschaften in eine zweite) drum herumkommen. Und als Nachschlagewert benötigst Du dan eine dritte. Also eine Tabelle für die Stammdaten, eine für die Nachschlagewerte der Eigenschaften und eine für die tatsächlich genutzen Eigenschaften.

    Liebe Grüße aus http://www.braunschweig.de

    Tom

    --
    Intelligenz ist die Fähigkeit, aus Fehlern Anderer zu lernen und Mut die, eigene zu machen.
    1. Hallo Tom,

      das ist mir schon klar. Ich will das ja auch genau so machen wie du es beschrieben hast.
      In der Eigentlichen Tabelle nur einen Set-Typ dessen Listen-Spalten als Namen nur eine ID bekommen. Und die Definition der Listenpunkte über Extra-Tabellen.

      Nur das Problem fängt da an das ich den Set-Typ nicht (oder nur mit unter 100 Werten angelegt bekommen (siehe oben).

      Beste Grüße - Verena

      1. Hallo Verena,

        Nur das Problem fängt da an das ich den Set-Typ nicht (oder nur mit unter 100 Werten angelegt bekommen (siehe oben).

        genau das hatte ich ja geschrieben. Aus den 8 Byte bekommt man eben nur 8*8=64 Optionen ehraus. Alle anderen Dokus sind schlichtweg falsch. Mehr kannst Du mit SET nicht schaffen.

        Liebe Grüße aus http://www.braunschweig.de

        Tom

        --
        Intelligenz ist die Fähigkeit, aus Fehlern Anderer zu lernen und Mut die, eigene zu machen.
        1. Hallo Tom,

          genau das hatte ich ja geschrieben. Aus den 8 Byte bekommt man eben nur 8*8=64 Optionen ehraus. Alle anderen Dokus sind schlichtweg falsch. Mehr kannst Du mit SET nicht schaffen.

          Hmmmmm... da scheinst du wirklich recht zu haben...
          Grmpf <-- weil ich jetzt meinen ganzen Plan umschmeißen muss!!

          Aber würd es denn Sinn machen da eine Tabelle anzulegen die dann im endeffkt vielleicht mal mehrere tausend Spalten und ebensoviele Einträge hat? Oder würd dann MySQL ins rudern kommen.
          Müsste ja immer als Wert nur 0 oder 1 drin stehen.

          Oder wie hattest du das dann gedacht?

          Beste Grüße und vor allem vielen Dank - Verena

          1. Hallo Verena,

            Aber würd es denn Sinn machen da eine Tabelle anzulegen die dann im endeffkt vielleicht mal mehrere tausend Spalten und ebensoviele Einträge hat? Oder würd dann MySQL ins rudern kommen.
            Müsste ja immer als Wert nur 0 oder 1 drin stehen.

            Oder wie hattest du das dann gedacht?

            Ich würde zwei Tabellen zusätzlich anlegen:

            z.B. für die Ausbildung einer Person:

            TABLE=Person
            ID_Person
            blah-felder
            ...

            TABLE=GetSkills
            ID_GetSkills
            Skills_Text
            blah-felder
            ...

            TABLE=ParsonHasSkills
            ID_PersonHasSkills
            ID_Person
            ID_GetSkills
            blah-felder
            ...

            Es gibt zum Beispiel vierhundert Berufe. Dann muss die Datenbank GetSkills vierhundert Datensätze enthalten, sagen wir mal von ID=1 bis ID=400.

            Nun hast Du zwanzig Personen

            Für jede Person gibt es in ParsonHasSkills n Einträge. Da steht dann eben z.B. drin

            ID_PersonHasSkills | ID_PERSON | ID_GetSkills
            -------------------+-----------+-------------
                      1        |      1    |       3        Person 1 hat Beruf 3
                      2        |      1    |       5        Person 1 hat (auch) Beruf 5
                      3        |      1    |      231       Person 1 hat (auch) Beruf 231
                      4        |      2    |       22       Person 2 hat Beruf 22
                      5        |      1    |       12                ...
                      6        |      3    |       333
                      7        |      3    |       2
                     ...

            So müsste es Dir klar werden, wie das Datenmodell aussehen könnte.

            Liebe Grüße aus http://www.braunschweig.de

            Tom

            --
            Intelligenz ist die Fähigkeit, aus Fehlern Anderer zu lernen und Mut die, eigene zu machen.
            1. Hallo Tom

              Es gibt zum Beispiel vierhundert Berufe. Dann muss die Datenbank GetSkills vierhundert Datensätze enthalten, sagen wir mal von ID=1 bis ID=400.

              Nun hast Du zwanzig Personen

              Aber wäre das auch noch effizient wenn es 4000 Berufe und 20000 Personen wären?

              5        |      1    |       12                ...
                        6        |      3    |       333
                        7        |      3    |       2
                       ...

              So müsste es Dir klar werden, wie das Datenmodell aussehen könnte.

              Ja doch, ich denke schon.

              Keine schlechte Idee. Hmmm...
              Also zwei Ideen, bzw. eine Idee mit zwei Variationen war das mit einem einfachen 'Gitter' aufzubauen:

              PERSON_ID | BERUF_1 | BERUF_2 | BERUF_3 | BERUF ..........
              ----------------------------------------------------------
                  0     |    0    |    0    |    1    |    0  ..........
                  1     |    1    |    0    |    1    |    0  ..........
                  2     |    0    |    1    |    0    |    1  ..........
                  3     |    1    |    0    |    0    |    1  ..........
                  4     |    1    |    1    |    0    |    1  ..........
                  5     |    0    |    0    |    0    |    0  ..........
                  6     |    1    |    1    |    1    |    0  ..........
                  7     |    0    |    0    |    0    |    1  ..........

              Oder Variation zwei, das selbe in komprimierter Form

              PERSON_ID | BERUFE                              ..........
              ----------------------------------------------------------
                  0     | 0010..........
                  1     | 1010..........
                  2     | 0101..........
                  3     | 1001..........
                  4     | 1101..........
                  5     | 0000..........
                  6     | 1110..........
                  7     | 0001..........

              (ich hoffe es wird klar was ich meine)

              Na ja, mal schauen wie ich das Problem lösen werde.

              Liebe Grüße - Verena

              1. Hallo Verena,

                Aber wäre das auch noch effizient wenn es 4000 Berufe und 20000 Personen wären?

                Ja, gerade dann wäre es effizeint. Denn nicht jede der 20.000 Personen wird alle 4.000 Beruf haben. Dann bräuchtest Du ja keine Datenbank mehr *gg*

                Mit dem normalisierten Modell wird ja nur immer dann ein Datensatz angelegt, wenn er benötigt wird, während in Deinem Modell (und auch beim Subtype SET) für jeden Beruf in jedem Personen-Datensatz ein Bit bereit gehalten werden muss. das steht dann entweder auf 0 oder 1.

                Die Bit-Zuordnungstabelle würde bei 4.000 Berufen 500 Byte pro Person verschlingen. Die 4.000 Klartextübersetzungen, die ich in die Tabelle GetSkills gepackt habe, würdest Du auch benötigen. Sie würden etwa genauso viel Platz benötigen.

                Ein Datensatz für HasSkills benötigt 24 Byte. Er setzt sich ja nur aus drei Schlüsseln zu je 8 Bytes (BigInt) zusammen. Da kann dann jeder 20 Datensätze haben, bis es mehr Speicherplatz kostet, als die Bitmuster-Variante. Den Primary-Key ID_HasSkills kann man auch weglassen, da ja ID_Person und ID_GetSkills zusammen einen Unique Key = Primärschlüssel geben. es ist ja nicht anzunehmen, dass eine Person eine Eigenschaft doppelt hat, oder? Dann könntst Du schon 31 Eigenschaften pro Person festhalten, bevor es mehr Speicherplatz als die Bitmustervariante kostet.

                Nun zur Frage, welche ist die richtige. Ich gehe davon aus, dass die 4.000 bisher entdeckten Berufe auf lange Sicht nicht mehr werden. Das heißt, dass man bei der Bitmustervariante die Tabelle in der statischen Richtung (horinzontal) nicht anfassen muss.

                Sollte die Zahl der Möglichkeiten aber dynamisch sein, (es kömmen welche hinzu, fallen wlche weg, ändern welche ihren Platz in der Reihenfolge), dann musst Du die in die dynamische Richtung der Tabelle legen, also in die Dateninhalte. Das würde für die Normalisierungsvariante sprechen.

                Oder Variation zwei, das selbe in komprimierter Form

                PERSON_ID | BERUFE                              ..........

                0     | 0010..........
                    1     | 1010..........
                    2     | 0101..........
                    3     | 1001..........
                    4     | 1101..........
                    5     | 0000..........
                    6     | 1110..........
                    7     | 0001..........

                Diese Variante ist ja im Prinzip die des "SET-Feldes". Du baust Dir einfach einen Blob oder ein xText-Feld und füllst es mit einem String, den Du natürlich vorher berechnen musst. Er enthält nur das Bitmuster.

                Das Zusammenstellen der aus den 4000 möglichen ausgewählten Eigenschaften dauert dann allerdings etwas länger. Du musst dann ja z.B. von rechts nach links den String im Speicher byteweise lesen (bitweise geht nicht) und den Wert in einen Tabelleneintrag umwandeln. Da fällt mir im Moment nicht ein, wie man das bezüglich der Rechenzeit schnell gestalten könnte.

                Und ein wesentlicher Punkt für das Design dürften die Abfragemöglichkeiten sein.

                In C oder Pascal kann man auch Strings bitweise vergleichen. Ob es in PHP oder Perl eine Möglichkeit dazu gibt, weiß ich im Moment nicht.

                (ich hoffe es wird klar was ich meine)

                Ja, total.

                Liebe Grüße aus http://www.braunschweig.de

                Tom

                --
                Intelligenz ist die Fähigkeit, aus Fehlern Anderer zu lernen und Mut die, eigene zu machen.