Peter: MYSQL Spaltenname von leeren Zellen ausgeben

Moin zusammen,
Ich hab ein Formular in das man sich bei bestimmten Zeiten eintragen kann. Natürlich sollen sich nicht zwei Personen zu der gleichen Zeit eintragen können, deswegen wollte ich gerne das nur der Name von leeren Spalten ausgegeben wird. Meine Tabelle sieht so aus:

CREATE TABLE `zeiten` (
 `ID` INT NOT NULL AUTO_INCREMENT ,
 `Name` VARCHAR(255) NOT NULL ,
 `15:00` VARCHAR(255) NOT NULL ,
 `15:05` VARCHAR(255) NOT NULL ,
 `15:10` VARCHAR(255) NOT NULL ,
 `15:15` VARCHAR(255) NOT NULL ,
 `15:20` VARCHAR(255) NOT NULL ,
 `15:25` VARCHAR(255) NOT NULL ,
 PRIMARY KEY (`ID`)) ENGINE = MyISAM;)

Das sind jetzt nur ein paar Spalten. Ich will nun mit einer Abfrage überprüfen welche Zellen in einer bestimmen Spalte leer sind und diese abrufen und anzeigen lassen. Der Anfang ist klar:

SELECT * FROM `zeiten` WHERE `Name` = 'Heinz' ...

Danach weiß ich nicht weiter, wie ich jetzt den Spaltenname nur von den Zellen bekomme die in der Zeile "Heinz" noch leer sind.
Hat jemand eine Idee? Muss ich die Tabelle evtl. anders aufbauen, damit das überhaupt irgendwie funktioniert?

Gruß
Peter

  1. Beschäftige Dich mal mit dem Thema Normalformen von Relationen. Ich weiß nicht genau, welche Normalform dein Konstrukt verletzt, aber es bestimmt eine dabei.

    Update: 1. Normalform - Eine Relation muss frei von Wiederholungsgruppen sein. Attribute, die gleiche oder gleichartige Information enthalten, müssen in eine andere Relation ausgelagert werden.

    Ich nehme an, dass zu jeder ID genau ein Name gehört. Dann modellierst Du eine Tabelle 1 mit ID und Name, und eine Tabelle 2 mit ID, Zeitpunkt und Belegungsfeld (VARCHAR(255) - bist Du sicher? kommen da etwa strukturierte Informationen hinein? Dann musst Du das in der Belegungstabelle aufteilen, ebenfalls eine Anforderung der 1. NF).

    Wenn Du die zweite Tabelle pro Name mit allen verfügbaren Zeitpunkten füllst, musst Du nach ID=4711 UND belegt=0 suchen und bekommst alle freien Zeiten.

    Rolf

  2. Tach!

    Das sind jetzt nur ein paar Spalten.

    Ja, und das wird unnötig groß, wenn noch mehr Zeiten hinzukommen.

    Ich will nun mit einer Abfrage überprüfen welche Zellen in einer bestimmen Spalte leer sind und diese abrufen und anzeigen lassen. Der Anfang ist klar:

    SELECT * FROM `zeiten` WHERE `Name` = 'Heinz' ...
    

    Ich gehe mal davon aus, dass Heinz nicht die Person ist, die sich eintragen will, sondern der Bearbeiter, der mit der Person einen Termin haben soll - oder so ähnlich. "Name" ist ein viel zu allgemeiner Begriff. Wenn es so ist, wie ich vermute, wäre "Bearbeiter" eine bessere Bezeichnung, die man weniger mit dem Namen von irgendwas/irgendwem anderen verwechseln kann.

    Danach weiß ich nicht weiter, wie ich jetzt den Spaltenname nur von den Zellen bekomme die in der Zeile "Heinz" noch leer sind.

    Das geht so nicht, weil du dann pro Spalte beziehungsweise Uhrzeit eine Abfrage brauchst. Diese Abfragen müssen dann mit UNION verbunden werden. Damit bekommst du ein "senkrechtes" Ergebnis, pro Zeit eine Zeile. Je Uhrzeit eine Abfrage ist jetzt nicht grad das, was man gern hätte.

    In der SELECT-Klausel kannst du keine variable Anzahl an Spalten haben. Das wäre aber das, worauf es hinausläuft, wenn du sozusagen ein waagerechtes Ergebnis haben möchtest (alles in einer Zeile).

    Datenbankseitig kannst du mit dem derzeitigen Tabellenformat am besten nur die Abfrage wie oben nehmen, ohne eine weitere Bedingung. Der Rest muss dann im auswertenden Programm erfolgen. Wenn du über die Spalten iterierst, kannst du feststellen, ob die Zeit belegt ist oder nicht.

    Hat jemand eine Idee? Muss ich die Tabelle evtl. anders aufbauen, damit das überhaupt irgendwie funktioniert?

    Tabellentechnisch wäre ein Aufbau mit den drei Spalten Bearbeiter, Uhrzeit (gegebenenfalls inklusive Datum) und Besucher besser. Du legst dann noch einen Unique Key über die beiden Felder Bearbeiter und Uhrzeit (ein Key über beide, nicht jeweils einen auf jede Spalte). Dann stellt bereits das DBMS sicher, dass es pro Berater und Uhrzeit keine zwei Einträge geben kann. Freie Termine belegen bei dem Design keinen Datensatz.

    Das bedeutet dann aber auch, dass du keinen kompletten Plan für alle Uhrzeiten direkt aus dem DBMS bekommen kannst. Du kannst nur alle Datensätze eingeschränkt pro Bearbeiter und vielleicht Tag holen, die existieren. Die Uhrzeiten müsstest du dann im abfragenden Programm erzeugen, um darüber iterieren zu können, beispielsweise mit der DatePeriod-Klasse. Zu jeder Uhrzeit fragst du dann die Ergebnismenge der Datenbankabfrage, ob eine Zeile vorhanden ist.

    Damit kannst du aber auch Abfragen recht einfach erstellen, wie: Gib mir alle Berater, die zu einer bestimmten Uhrzeit keinen Eintrag haben. Vorausgesetzt, es gibt eine weitere Tabelle mit allen Beratern, an die man dann mit einem Left Join die Uhrzeiten anbinden kann. Wenn statt einem Eintrag aus der Uhrzeiten-Tabelle ein NULL kommt, ist der Berater zu dieser Zeit verfügbar.

    dedlfix.

    1. Hi,
      ich hab das jetzt alles geändert und umgeschrieben. Ich bekomme es jetzt nur noch nicht hin das die Uhrzeiten erzeugt werden. Das Datum spielt keine Rolle (Ich hab jetzt einfach mal den 1.1.2001 genommen), ich brauch einfach nur an dem Tag die Zeiten von 15 bis 19 Uhr. Ich hab das mit der DatePeriod-Klasse versucht bekomme das aber nicht hin. Das ist mein Code:

      $beginn = new DateTime('2001-01-01 15:00:00');
      $end = new DateTime('2001-01-01 19:00:00');
      $inteval = new DateInterval('PT5M');
      $timerange = new DatePeriod($beginn, $interval, $end);
         
      foreach($timerange as $date){
          echo $date->format("H:i") . "<br>";
      }
      

      Wenn ich das ausführe bekomme ich folgenden Fehler:
      Fatal error: Uncaught exception 'Exception' with message 'DatePeriod::__construct(): This constructor accepts either (DateTimeInterface, DateInterval, int) OR (DateTimeInterface, DateInterval, DateTime) OR (string) as arguments.'

      Was mache ich falsch?
      Danke schon mal
      Peter

      1. Tach!

        Wenn ich das ausführe bekomme ich folgenden Fehler:
        Fatal error: Uncaught exception 'Exception' with message 'DatePeriod::__construct(): This constructor accepts either (DateTimeInterface, DateInterval, int) OR (DateTimeInterface, DateInterval, DateTime) OR (string) as arguments.'

        Das ist ein Folgefehler. Der eigentliche ist ein Tippfehler bei einem Variablennamen.

        Was mache ich falsch?

        Du hast das error_reporting nicht auf E_ALL stehen. Das hätte dir die Ungereimtheit bei den Variablen angezeigt.

        dedlfix.

        1. Ok, habs jetzt

          Danke

          1. Ok, ich habs doch noch nicht :( Also ich hab jetzt die Ausgabe aller Zeiten hinbekommen, aber irgendwie klappt das abfragen ob die Zeit schon vorhanden ist nicht. Ich hab das auf unterschiedliche weisen versucht, aber es wird immer nur der erste Eintrag nicht angezeigt, der schon in der DB ist. Das liegt wahrscheinlich daran, dass das beides Arrays sind, oder? Wie bekomme ich den Vergleich so hin, das alle schon eingetragenen Uhrzeiten nicht angezeigt werden?

            $data = sprintf(
            	"SELECT `Uhrzeit`
            	FROM `Zeiten` 
            	WHERE `Name` = 'Friedrichsen'"
            );
            $query = $mysqli->query($data);
            $row = $query->fetch_array(MYSQLI_ASSOC);
            
            $beginn = new DateTime('2001-01-01 15:00:00');
            $end = new DateTime('2001-01-01 19:05:00');
            $interval = new DateInterval('PT5M');
            $timerange = new DatePeriod($beginn, $interval, $end);
            
            foreach($timerange as $date){
            	$time = $date->format('H:i');
            	if($row['Uhrzeit'] != $time){
            		echo $time . '<br>';
            	}
            } 
            

            Das ist der Code den ich bis jetzt habe. Als beispiel Datensätze hatte ich 15:05 und 15:15 eingetragen, aber nur 15:05 wird nicht angezeigt.

            Vielen Dank schon mal
            Peter

            1. Tach!

              Also ich hab jetzt die Ausgabe aller Zeiten hinbekommen, aber irgendwie klappt das abfragen ob die Zeit schon vorhanden ist nicht.

              Der erste Teil sollte sein, dass du die Ergebnismenge der Datenbankabfrage durchläufst und damit ein Array anlegst (zum Beispiel $zeiten = array();). Wenn du nur die Uhrzeit brauchst, leg diese als Wert in die Array-Elemente und lass die Keys automatisch vergeben. $zeiten[] = $row['Uhrzeit']; Dann kannst du im nächsten Teil mit in_array($uhrzeit, $zeiten) prüfen, ob es die Uhrzeit gibt.

              Brauchst du mehr Daten als die Uhrzeit, dann leg die ganze Zeile als Unterarray in dein Array und nimm als Key die Uhrzeit. $zeiten[$row['Uhrzeit']] = $row; Dann kannst du mit isset($zeiten[$uhrzeit]) prüfen, ob es die Uhrzeit gibt (oder mit array_key_exists()).

              dedlfix.

              1. Hi,
                Herzlich Dank dedlfix. Jetzt hab ich es endlich hinbekommen. Hab gar nicht an in_array gedacht, ist schon viel zu spät :)

                Gruß
                Peter

  3. Hello,

    Du möchtest also Überlappungen von Zeiträumen vermeiden? Wenn ja, dann gibt es hier im Archiv bessere Lösungen.
    Wenn Du willst, finden wir mit etwas Glück einige wieder. Sag Bescheid.

    Liebe Grüße
    Tom S.

    --
    Es gibt nichts Gutes, außer man tut es
    Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
    1. Hallo Tom,
      genau das brauch ich. Ich würde mir die anderen Lösungen gerne mal anschauen.
      Wo finde ich die?

      Gruß
      Peter

      1. Hello,

        genau das brauch ich. Ich würde mir die anderen Lösungen gerne mal anschauen.
        Wo finde ich die?

        im Archiv mit der Suche

        Suchstring musst Du korrigieren: tag:datenbank termin

        zum Beispiel dieser Thread

        Es gibt aber noch älterd Threads dazu mit Erläuterung des Lösungswegs (siehe Suchetgebnis)

        Liebe Grüße
        Tom S.

        --
        Es gibt nichts Gutes, außer man tut es
        Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
        1. Hi,
          Ich hab mir jetzt ein paar der alten Threads angeschaut, aber ich werde da irgendiwe nicht so wirklich schlau draus.

          Trotzdem vielen Dank
          Peter

          1. Hello,

            Ich hab mir jetzt ein paar der alten Threads angeschaut, aber ich werde da irgendiwe nicht so wirklich schlau draus.

            Vorausgesetzt, ich habe dein Uranliegen richtig verstanden, dann schau dir nochmal dieses mySQL-Statement an. Du brauchst nicht esrst abzufragen, ob der Terminzeitraum noch frei ist, sondern versuchst einfach, den neuen Termin mit dem Statement einzufügen. Wenn es geklappt hat, ist num_rows === 1, sonst ist es 0.

            Dies wäre dann die passende Methode, um konkurrierenden Betrieb möglich zu machen, ohne Überlappungen zu riskieren.

            Liebe Grüße
            Tom S.

            --
            Es gibt nichts Gutes, außer man tut es
            Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
            1. Uranliegen

              Oha. Liegestühle made in Fukushima, mit Liegekissen aus ukrainischer Produktion (Werk Prypyat) für strahlende Sonnentage.

              Rolf

              1. Hej Rolf,

                Uranliegen

                Oha. Liegestühle made in Fukushima, mit Liegekissen aus ukrainischer Produktion (Werk Prypyat) für strahlende Sonnentage.

                Darauf einen Harrisburger!

                Marc

                1. Hello,

                  Uranliegen

                  Oha. Liegestühle made in Fukushima, mit Liegekissen aus ukrainischer Produktion (Werk Prypyat) für strahlende Sonnentage.

                  Darauf einen Harrisburger!

                  Oder doch besser eine Pizza mit Digitalkäse? Davon haben wir ja hier genug ;-P

                  Liebe Grüße
                  Tom S.

                  --
                  Es gibt nichts Gutes, außer man tut es
                  Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.