Bernd: Mehrere Werte in einem Feld speichern?

Hallo,

ich lese für einen Filter wie folgt Daten aus

<form method="post"> 
    <ul style="padding-left: 0;">
    <?php foreach($frontend_Zeiterfassung as $array_menschen){ ?>
      <label style="display: block;">
        <input
            type="checkbox" 
            name="menschen[]"
            value="<?php echo htmlspecialchars($array_menschen['per_code']); ?>">
            <?php echo $array_menschen['per_vorname'] ." ". $array_menschen['per_name'];?>
      </label>
    <?php } ?>
    </ul>
    <button type="submit" name="action">Filter anwenden</button> 
  </form>

Da jeder User seinen eigenen Filter setzten kann dachte ich, ich speichere die Werte in meiner User-Tabelle in einem weiteren Feld ab. Ist dieses möglich oder soll ich für solche Aktionen eine weitere Tabelle in meiner Datenbank anlegen? Wenn das speichern in einem Feld gehen würde, gibt es vor und Nachteile gegenüber einer eigenen Tabelle?

Die Daten, die ich über den Filter bekomme, benötige ich später in dieser Funktion

$frontend_Zeiterfassung = Zeiterfassung ($mysqli);

Hier muss ich dann ein array mit den Werten übergeben, die ich eben _nicht_sehen möchte.

  1. Tach!

    Da jeder User seinen eigenen Filter setzten kann dachte ich, ich speichere die Werte in meiner User-Tabelle in einem weiteren Feld ab. Ist dieses möglich oder soll ich für solche Aktionen eine weitere Tabelle in meiner Datenbank anlegen?

    Man kann immer Daten serialisieren, im einfachsten Fall mehrere Strings durch ein Trennzeichen getrennt aneinanderhängen. Und man kann solcherart erzeugten String wie jeden anderen String in einem String-Feld im DBMS ablegen. Die Frage ist, ob man das tun sollte.

    Solange das DBMS nur ein Datengrab ist und diese Daten entgegennimmt und wieder hergibt, ist es kein Thema, in welchem konkreten Format die Daten vorliegen. Sobald aber das DBMS diese Daten selbst verarbeiten muss - in der Form, dass daraus nur ein Teil benötigt wird - bekommt man ein Problem, diesen Teil zu extrahieren.

    Für das DBMS wäre also zu klären, ob es Teile verarbeiten muss oder ihm der Inhalt egal ist. Wenn letzteres, dann ist es mehr oder weniger lediglich eine Frage der Vorliebe und des Aufwandes, den man in der Anwendung betreiben möchte, um die Daten entweder gemeinsam aus einem Feld (plus Deserialisierung) oder einzeln aus vielen Datensätzen zu holen. Bedenke aber, dass eine Entscheidung zum Kompaktformat sich später als nachteilig herausstellen kann, wenn sich die Voraussetzungen oder Wünsche ändern, und man mit dem DBMS dann doch auf Teile zugreifen möchte. Ich glaube, du warst derjenige, der das Problem in ähnlicher Form bereits beim falschen DBMS-Format für Datum und/oder Preise kennengelernt hat.

    dedlfix.

    1. Hallo,

      danke für deine Erklärung. OK, um auf Nummer sicher zu gehen speichere ich die Daten in einer weiteren Tabelle. Einer Webseite ist es ja egal wie viele Tabellen im Hintergrund arbeiten?

      Ich habe es nur in Wordpress gesehen dass da sehr viele Werte / Einstellungen in einem Feld liegen.

  2. hi Bernd,

    Deine Frage betrifft den wahlfreien Zugriff. Überlege Doch einmal selbst, was zweckmäßiger ist, z.B. bei der Suche eines bestimmten Schreiben vom Finanzamt: Jedesmal einen Briefumschlag zu öffnen und das Schreiben herausnehmen oder in einen Ordner durchzublättern wo die einzelnen Schreiben abgeheftet sind!?

    Genauso ist das mit Deiner Datenvearbeitung.

    MfG

    1. Tach!

      Deine Frage betrifft den wahlfreien Zugriff.

      Den man nicht unbedingt im DBMS braucht.

      Überlege Doch einmal selbst, was zweckmäßiger ist, z.B. bei der Suche eines bestimmten Schreiben vom Finanzamt: Jedesmal einen Briefumschlag zu öffnen und das Schreiben herausnehmen oder in einen Ordner durchzublättern wo die einzelnen Schreiben abgeheftet sind!?

      Der Vergleich passt nicht ganz. Die Schreiben sind ohne Briefumschlag. Ein Briefumschlag wäre in etwa mit einer zusätzlichen Komprimierung einzelner Datensätze zu vergleichen. Es geht hier aber eher darum, sich entweder vom DBMS den Ordner mit den abgehefteten Scheiben oder alle Schreiben als lose Blattsammlung geben zu lassen, in beiden Fällen ohne Briefumschlag. Das Auspacken bei einer Speicherung als Serialisierung ist eher mit dem Aufschlagen des Ordners und dem Lösen des Niederhalters zu vergleichen, der alle Schreiben festhält.

      Was davon zweckmäßig ist, ist ohne den Verwendungszweck nicht beantwortbar. Bei Finanzamtsschreiben wird es wohl eher so sein, dass man auch mal einzelne braucht. Ob man aber im Falle des OP solche einzelnen oder stets alle Datensätze gemeinsam braucht, ist ein bedeutender Unterschied in der Beurteilung der Zweckmäßigkeit und damit der Frage, an welcher Stelle der wahlfreie Zugriff benötigt wird. Schon im DBMS oder erst in der Anwendung.

      dedlfix.

  3. Es gibt als Datentype das "SET".

    CREATE TABLE `filter` (
        `userID` INT,
        `filter` SET('PauseBeginn', 'PauseEnde' ,'Kommen', 'Gehen' ),
        INDEX (`userID`)
    )
    

    Danach kann in die Tabelle wie folgt eingetragen werden:

    INSERT INTO `filter` ( `userID` , `filter` ) VALUES ( 1, 'PauseBeginn' );
    SELECT `filter` FROM `filter` WHERE `userID` = 1;
    

    userID|filter 1|PauseBeginn

    Filter hinzufügen:

    UPDATE `filter` SET `filter` = CONCAT(`filter` , ',', 'PauseEnde') WHERE `userID`=1;
    SELECT `userID`, `filter` FROM `filter` WHERE `userID` = 1;
    

    userID|filter 1|PauseBeginn, PauseEnde

    Index setzen und nach Filter abfragen:

    ALTER TABLE `filter` ADD INDEX `filter` ( `filter` )
    SELECT `userID`, `filter` FROM `filter` WHERE FIND_IN_SET( 'PauseEnde',`filter` );
    

    userID|filter 1|PauseBeginn, PauseEnde

    Entfernung eines Filters:

    UPDATE `filter` SET `filter` = REPLACE( `filter` , 'PauseBeginn', '' )
    

    userID|filter 1|PauseEnde

    Versuch eines bei der Spaltendefinition nicht definierten Eintrages:

    UPDATE `filter` SET `filter` = 'Nicht Definiert' WHERE `userID`=1;
    SELECT `userID`, `filter` FROM `filter` WHERE `userID` = 1;
    

    userID|filter 1|

    1. Tach!

      Es gibt als Datentype das "SET".

      Einschränkung: Der Datentyp SET ist anwendbar, wenn die Liste der Werte unveränderlich feststeht. Ansonsten müsste man das Tabellenlayout ändern, um Werte hinzuzufügen oder zu entfernen.

      Aber da sehe ich gleich noch etwas im OP, das ich in meiner ersten Antwort nicht beachtet hatte.

      Hier [bei einer DBMS-Abfrage] muss ich dann ein array mit den Werten übergeben, die ich eben _nicht_sehen möchte.

      In dem Fall sieht es so aus, dass die Werte einzeln benötigt werden, weil sie Suchkriterium für andere Datensätze sind. Man kann sie zwar kommasepariert speichern und dann mit FIND_IN_SET() was zaubern (das arbeitet neben dem Feldtyp SET auch mit kommaseparierten Strings), aber das wird auf einen Full-Table-Scan hinauslaufen. Besser ist dann eine Tabelle mit einzelnen Datensätzen pro Wert. Dann kann man mit IN() oder NOT IN() plus Subquery auf ebendiese Datensätze innerhalb des IN() besser darauf zugreifen.

      SELECT .. 
      FROM irgendwo 
      WHERE kriteriumsfeld NOT IN(SELECT value FROM andere_tabelle WHERE person = irgendwer)
      

      dedlfix.

      1. Einschränkung: Der Datentyp SET ist anwendbar, wenn die Liste der Werte unveränderlich feststeht.

        Ja. Ich hab der Beschreibung entnommen, dass es womöglich so ist.

        Hier [bei einer DBMS-Abfrage] muss ich dann ein array mit den Werten übergeben, die ich eben _nicht_sehen möchte.

        Eben deshalb.

        Man kann sie zwar kommasepariert speichern und dann mit FIND_IN_SET() was zaubern (das arbeitet neben dem Feldtyp SET auch mit kommaseparierten Strings), aber das wird auf einen Full-Table-Scan hinauslaufen.

        Ja. In dem Fall, dass man die Einträge mit einen der Werte finden soll ist das SET nicht optimal

    2. Es gibt als Datentype das "SET".

      Für Zeiterfassung völlig ungeeignet weil bei einer Zeitart (Urlaub, Dienstreise usw) die Konsistens nicht sichergestellt werden kann (Begin, Ende fehlt, Beginn > Ende usw.). Ein zweckmäßiges Datenmodell hab ich hier übrigens unlängst vorgestellt, schließlich habe ich auch mal eine Zeiterfassung progammiert. Und zwar eine die sich produktiv bewährt hat mit Schnittstelle zu SAP.

      MfG

    3. CREATE TABLE `filter` (
          `userID` INT,
          `filter` SET('PauseBeginn', 'PauseEnde' ,'Kommen', 'Gehen' ),
          INDEX (`userID`)
      )
      

      Alternative Syntax für Updates, Inserts

      UPDATE `filter` SET `filter` = 9;
      

      userID|filter 1|PauseBeginn,Gehen

      Grund: SET('PauseBeginn', 'PauseEnde' ,'Kommen', 'Gehen' )

      PauseBeginn = 1 (2^0)
      PauseEnde   = 2 (2^1) 
      Kommen      = 4 (2^2)
      Gehen       = 8 (2^3)
      

      PauseBeginn + Kommen = 9

      UPDATE `filter` SET `filter` = filter -8 WHERE userID =1
      

      userID|filter 1|PauseBeginn