Announcement

Collapse
No announcement yet.

Leerzeiten in der Vermietung finden

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Leerzeiten in der Vermietung finden

    Für meine Frau habe ich eine Homepage zur Präsentation von Ferienwohnungen geschrieben mit PHP und Mysql. Jetzt habe ich mich getraut die Belegungszeiten in einer Tabelle zu hinterlegen

    id int(11) auto
    infdat int(14) - aktualisierungsdatum mit timestamp
    obj_nr varchar(15)
    von date
    bis date

    Dies habe ich gemacht, um im Abgleich mit der Objektdatentabelle freie Objekte zu finden. Es funktioniert.

    Code:
    select `db_gastgeber`.* 
    		from `db_gastgeber` 
    		left join `cc_gastgeber_belegung` 
    		on `db_gastgeber`.`obj_nr` = `cc_gastgeber_belegung`.`obj_nr`  
    		and ((`cc_gastgeber_belegung`.`von` < '".$dat_bis."' and `cc_gastgeber_belegung`.`bis` > '".$dat_von."')
    		or   (`cc_gastgeber_belegung`.`von`  <= '".$dat_von."' and `cc_gastgeber_belegung`.`bis`  >= '".$dat_bis."'))
    		where `db_gastgeber`.`on` = 1 and `cc_gastgeber_belegung`.`obj_nr` is NULL
    		order by `db_gastgeber`.`obj_nr`
    Wenn ich ein Anfangs- und Enddatum eingebe, klappt es. Nun habe ich das Problem

    In der Zeit von ...... bis ...... möchte der user nur 7 Tage.

    Das geht damit nicht bzw. hab keine Möglichkeit gefunden.

    Meine Frage:

    Sieht jemand eine Lösung?

    oder

    Muss ich die Belegungsdatentabelle anders aufbauen?

    Über konstruktive Vorschläge würde ich mich riesig freuen.

    MfG coastbike
    Zuletzt editiert von coastbike; 03.05.2007, 12:09. Reason: Thema geändert

  • #2
    Hallo,

    In der Zeit von ...... bis ...... möchte der user nur 7 Tage.
    nur um sicherzugehen: Ist damit gemeint, dass als Ergebnis der 1. passende Abschnitt von 7 aufeinanderfolgenden Tagen aus einem Bereich von mehreren Wochen benötigt wird, an dem das Objekt noch unbelegt ist?

    Comment


    • #3
      Erstmal danke für die schnelle Reaktion.

      JA!

      Also! Gemeint ist - in der Zeit vom 01.06.07 bis 30.06.07 will der user 7 zusammenhängende Tage mieten -

      Reicht Dir das?

      Oder soll ich vielleicht sagen: in der Zeit ein Fenster finden, das >= 7 Tage ist.

      Comment


      • #4
        Hallo coastbike,

        ich glaube nicht das sich diese Problem mit einer einzelnen SQL-Abfrage lösen läßt, noch dazu die Möglichkeiten von Subselects in MySQL sehr beschränckt sind.
        Ich würde einen Rekursiven Ansatz wählen. Du hast eine Funktion mit einem Anfangs- und einem Enddatum, sowie der Dauer als Parameter.
        Zuerst wird überprüft ob der Zeitraum zwischen Anfang und Ende überhaupt >= Dauer ist, wenn ja dann wird jetzt mit SQL
        Code:
        SELECT MIN(bis date) first_date, MAX(von date) last_date
        FROM db_gastgeber
        WHERE bis date >= :DatumVon
          OR von date <= :DatumBis
        das jeweils kleinste End- und das größte Anfangsdatum aller Buchungen im gesuchten Zeitraum ermittelt. Einen passenden Zeitraum gibt es wenn:
        1. kein DS gefunden wurde,
        2. zwischen :last_date und Enddatum mehr oder gleich Dauer Tage liegen
        3. zwischen :first_date und Anfangsdatum mehr oder gleich Dauer Tage liegen
        In allen anderen Fällen wird die Funktion selber wieder mit :first_date und :last_date als Werten für die Parameter Anfangsdatum und Enddatum aufgerufen.

        Aber Achtung, Rekursionen sollten gut durchdacht sein, um Endlosschleifen zu vermeiden. Mein Ansatz ist nicht getestet und kann durchaus unerwünschte Ergebnisse haben Z.B. könnte es durchaus notwendig sein, die Prüfung date >= : DatumVon bzw. von date <= : DatumBis in nur < bzw. > zu ändern.

        Gruß Falk
        Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

        Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

        Comment


        • #5
          Hallo Frank,

          danke für Deine Antwort. Also bist Du der Meinung, ich sollte die Belegungstabelle so lassen und nur die Abfrage neu gestalten. Ich werde es auf jeden Fall probieren und melde mich.

          MfG coastbike

          Comment


          • #6
            Originally posted by coastbike View Post
            ...Also bist Du der Meinung, ich sollte die Belegungstabelle so lassen und nur die Abfrage neu gestalten. ...
            Hallo coastbike,
            gegen deine Tabelle gibt es nichts einzuwenden . Dein geschildertes Problem läßt sich meines Erachtens NICHT mit einer EINZELNEN (MySQL) SQL-Abfrage lösen, egal wie die Tabelle gestaltet ist. Nicht umsonst verfügen alle "großen" Datenbanken über die Möglichkeit eigene Funktionen anzulegen.

            Originally posted by coastbike View Post
            Hallo Frank, ...
            Ich heiße übrigens Falk aber Namen sind eh Schall und Rauch

            Gruß Falk
            Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

            Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

            Comment


            • #7
              Hallo Falk,

              danke für die letzte Info. In Kurzform, was ich heute gemacht habe. Also:

              1. Im Formular die Reisedauer ($dauer) eingebaut
              2.
              Code:
              $dat_von_array = explode (".",$datum1);						// von aus Formular
              $dat_von = $dat_von_array[2]."-".$dat_von_array[1]."-".$dat_von_array[0];	// mysql-Datum
              $datvon = $dat_von_array[0].".".$dat_von_array[1].".".$dat_von_array[2];	// europ. Datum 
              $dat_bis_array = explode (".",$datum2);						// bis aus Formular
              $dat_bis = $dat_bis_array[2]."-".$dat_bis_array[1]."-".$dat_bis_array[0];	// mysql-Datum
              $datbis = $dat_bis_array[0].".".$dat_bis_array[1].".".$dat_bis_array[2];	// europ. Datum
              $timestamp_von = mktime(0,0,0,$dat_von_array[1],$dat_von_array[0],$dat_von_array[2]);
              $timestamp_bis = mktime(0,0,0,$dat_bis_array[1],$dat_bis_array[0],$dat_bis_array[2]);
              $dat_diff = ($timestamp_bis - $timestamp_von)/24/60/60;				// Diff zwischen von und bis
              $start = (empty($dauer) or $dauer > $dat_diff) ?$dat_von :date("Y-m-d",mktime(0,0,0,$dat_von_array[1],$dat_von_array[0]+$dauer,$dat_von_array[2]));
              $end = (empty($dauer) or $dauer > $dat_diff) ?$dat_bis :date("Y-m-d",mktime(0,0,0,$dat_bis_array[1],$dat_bis_array[0]-$dauer,$dat_bis_array[2]));
              3. neue Werte in die Abfrage eingebaut
              Code:
              $sql = "select `db_gastgeber`.* 
              	from `db_gastgeber` 
              	left join `cc_gastgeber_belegung` 
              	on `db_gastgeber`.`obj_nr` = `cc_gastgeber_belegung`.`obj_nr`  
              	and ((`cc_gastgeber_belegung`.`von` < '".$end."' and `cc_gastgeber_belegung`.`bis` > '".$start."')
              	or   (`cc_gastgeber_belegung`.`von`  <= '".$start."' and `cc_gastgeber_belegung`.`bis`  >= '".$end."'))
              	where `db_gastgeber`.`on` = 1 and `cc_gastgeber_belegung`.`obj_nr` is NULL
              	order by `db_gastgeber`.`obj_nr`";
              Funzt! Bis auf eine Kleinigkeit. Wenn ich im Zeitfenster 2 Belegungen für ein Objekt habe und die erste hat bis zum Ende des Zeitfensters >=$dauer oder die zweite Belegung hat bis zum Anfang >=$dauer, dann zeigt er mir das Objekt auch an, weil er jeden Datensatz extra auswertet. Was nun?

              Übrigens Falk, mit Deinem Script bin ich nicht ganz klar gekommen, aber
              2. zwischen :last_date und Enddatum mehr oder gleich Dauer Tage liegen
              3. zwischen :first_date und Anfangsdatum mehr oder gleich Dauer Tage liegen
              hat mich auf die Idee gebracht. Nochmals Danke!

              MfG coastbike
              Zuletzt editiert von coastbike; 04.05.2007, 19:54.

              Comment


              • #8
                Hallo coastbike,

                wie du gemerkt hast (und ich bereits gesagte habe), läßt sich das Problem nich mit einer einfachen SQL-Abfrage lösen. Deshalb habe ich den Weg über eine zusätzliche Funktion vorgeschlagen, die eine rekursive Prüfung vornimmt, bis entweder ein freier Bereich am Anfang oder Ende gefunden wird.

                Ich gehe davon aus das du PHP als Scriptstprache für deine Anwenbdung verwendest. Hier mal zur Verdeutlichung ein wenig Code, um zu Zeigen was ich meine.
                PHP Code:
                /* $pVon - Unix-Timestamp
                   $pBis - Unix-Timestamp */
                function getMinMaxDate($pVon$pBis)
                {
                  
                /* Diese function ermittelt das jeweils kleinste End- und das größte Anfangsdatum
                     aller Buchungen im gesuchten Zeitraum und liefert das Ergebnis in einem Array
                     mit 'first_date' für das größte Anfangsdatum und 'last_date' für das kleinste
                     Enddatum
                     Der Rückgabewert ist FALSE, falls kein DS gefunden wird.
                     'first_date' und 'last_date' werden als Unix-Timestamp zurückgegeben */
                  
                ...
                }

                /* $pVon - Unix-Timestamp
                   $pBis - Unix-Timestamp
                   $pTage - Ganzzahl */
                function getBelegung($pVon$pBis$pTage)
                {
                  if (
                $pBis $pVon $pTage)
                    return 
                false// Zeitraum zu klein, kein Treffer möglich
                  
                $MinMax getMinMaxDate($pVon$pBis);
                  if (!
                $MinMax)
                    return 
                true// kein MinMax-Datum - Zeitraum komplett frei
                  
                if ($pBis $MinMax['last_date'] => $pTage)
                    return 
                true// Zeitraum am Ende frei
                  
                if ($MinMax['first_date'] - $pVon => $pTage)
                    return 
                true// Zeitraum am Anfang frei

                  
                return getBelegung($MinMax['first_date'], $MinMax['last_date'], $pTage); // Achtung Rekursion!

                Die Funktion getMinMaxDate() mußt du noch mit Leben füllen, also SQL-String zusammenbauen, DB-Abfrage (siehe meinen Thread weiter unten), evtl. Ergebiswerte konvertieren.

                Ansonsten gilt zur Rekursion das bereits Gesagte .

                Gruß Falk
                Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

                Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

                Comment


                • #9
                  Hallo Falk!

                  Erstmal danke. Hab Deine Nachricht in der Post gefunden. Wenn ich vom Außendiest zurück bin, werde ich mich der Sache annehmen. Melde mich dann wieder. Bis dann! coastbike

                  Comment


                  • #10
                    Hallo Falk! Also nochmals vielen Dank.

                    Das ich nicht so schnell durchsehe, liegt vielleicht daran, dass ich mich noch nicht allzu lange mit PHP und MySql beschäftige. Alles autodidaktisch. Vielleicht muss ich aber auch noch einmal zur Basis zurück. Also!

                    Es gibt 2 Tabellen in der Datenbank, die verwendet werden.

                    1. `db_gastgeber` – alle vorhanden Objekte mit Beschreibung
                    a. Spalte `obj_nr` als Identifikation des Objektes
                    2. `cc_gastgeber_belegung` – alle Belegungen der Objekte
                    a. Spalte `obj_nr` als Identifikation des Objektes
                    b. Spalte `von` für Anreisetag
                    c. Spalte `bis` für Abreisetag, wobei Abreisetag und nächster Anreisetag des selben Objektes identisch sein darf

                    Aus dem Formular werden folgende Daten übergeben:

                    • $dat_von (format `YYYY-mm-dd`)
                    • $dat_bis (format dito)
                    • $dauer (format Ganzzahl)

                    Die Umwandlung des Datums in timestamp ist kein Problem.

                    Zur Begriffserklärung noch Folgendes. Im weiteren Text werde ich für den Zeitraum

                    • $dat_von - $dat_bis den Begriff Zeitfenster und für
                    • $dauer den Begriff Reisedauer verwenden.

                    Womit ich bei Deinem ersten Code nicht klar kam, ist atumVon und atumBis, wobei ich den Doppelpunkt meine. Nach langen überlegen interpretiere ich das mal so

                    atumVon entspricht $dat_von aus dem Formular und
                    atumBis entspricht dann $dat_bis

                    Also müsste dann Deine Select-Abfrage so geschrieben werden:

                    PHP Code:
                    SELECT MIN(`bis`) first_dateMAX(`von`) last_date
                    FROM 
                    `cc_gastgeber_belegung`
                    WHERE `bis` >= $dat_von
                      
                    OR `von` <= $dat_bis 
                    Nach Berücksichtigung von Orthografie und Grammatik für Select-Abfragen bekomme ich als Ergebnis :-( 0 Treffer. Dazu muss ich sagen, dass $dat_von und $dat_bis im Format der Datenbank eingesetzt wurden (YYY-mm-dd).

                    Aber unabhängig davon, sollte ich vielleicht doch einmal die möglichen Sonderfälle der Buchungen anführen, die gesucht werden:
                    1. `von` < $dat_von and `bis` > $dat_bis (Buchung ist größer als das Zeitfenster)
                    2. `von` < $dat_von and `bis` > $dat_von and `bis` <= $dat_bis
                    3. `von` >= $dat_von and `von` < $dat_bis and `bis` > $dat_bis
                    4. `von` >= $dat_von and `bis` <= $dat_bis
                    5. Und in ganz besonderen Fällen sind im Zeitfenster mehr als eine Buchung, die entweder Anfang und Ende des Zeitfensters schneiden und somit im Mittelbereich Platz für eine Buchung der Reisedauer lassen, oder ein oder mehrere Buchungen innerhalb des Zeitfensters sich befinden und/oder eine Buchung den Anfang und/oder eine Buchung das Ende des Zeitfensters schneiden.

                    In Excel habe ich mal so was gemacht. Find es leider nicht mehr. War auch sehr aufwendig. Da habe ich nach und nach jede Wohnung nach Buchungen im Zeitfenster abgefragt und habe bei Zwischenräumen >= Reisedauer das Objekt in ein Array abgespeichert. Zum Schluss habe ich aus dem Array alle Doppelnennungen rausgeschmissen und hatte somit eine Liste mit möglichen Objekten.

                    So! Das musste noch raus. Und jetzt zu Deinem 2. Code.

                    Ich gehe davon aus, dass

                    $pVon dem $dat_von aus dem Formular entspricht und demzufolge
                    $pBis dem $dat_bis und
                    $pTage dem $dauer

                    Und wenn ich, so verstehe ich es jedenfalls, Deine Erläuterung der Funktion
                    PHP Code:
                    /*Diese function ermittelt das jeweils kleinste End- und das größte Anfangsdatum aller
                    Buchungen im gesuchten Zeitraum und liefert... */ 
                    auf ein geprüftes Objekt beziehe, fange ich an zu verstehen.

                    Also!
                    1. Suche alle Belegungen, die das Zeitfenster berühren oder darin liegen
                    2. ordne sie den Objekten zu und berechne die Zwischenräume
                    3. Wähle alle Objekte aus, die keine Belegung bzw. die einen Zwischenraum von >= Reisedauer haben

                    Knobel, knobel, knobel!

                    Kann ich Deinen Darlegung so verstehen?

                    Mit freundlichen Grüßen coastbike

                    Comment


                    • #11
                      Hallo coastbike,

                      da haben wir irgendwie klassisch aneinander vorbeigeredet, d.h. wohl eher ich habe nicht genau verstanden (oder gelesen ) was deine Voraussetzungen sind. Ich habe bei meiner Lösung z.B. überhaupt nicht berücksichtigt, das es mehrere Objekte geben kann und die in der Belegungstabelle nicht unbedingt vorkommen müssen, da sie komplett frei sind. Meine Lösung würde diese Objekte NICHT finden. Und das ich mich nicht an deine Namenskonventionen gehalten habe hat es mit Sicherheit auch nicht einfacher gemacht. Sorry, wenn ich dich gehörig durcheinander gebracht habe.
                      Werde mir deinen letzten Post noch mal in Ruhe ansehen und über eine Lösung nachdenken und mich dann nochmal melden. (Kann ein wenig dauern ) Bisweilen kannst du schonmal alles von mir zu dem Thema Gesagte in die Tonne treten.

                      Gruß Falk
                      Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

                      Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

                      Comment


                      • #12
                        Hallo Falk,

                        nicht so schlimm. Hat mir bisher trotzdem schon was gegeben. Auch wenn's nicht richtig passt. Mein letzter Beitrag entstand genau aus der Vermutung

                        +++ Diskussion im Gegenverkehr +++
                        .
                        PHP und MySql sind für mich ein neues aber gewolltes Gebiet. Anstoß war eigentlich mein gekauftes Portal http://zingst-info.de. Da bin ich auf den Geschmack gekommen. Und Datenbanken haben mich schon immer interessiert. Konnte bloß bisher noch nicht viel damit anfangen. Da hab ich einfach gedacht, schreibst mal was für deine Frau. Dass das gleich so ausufert, konnte ich nicht ahnen. Deshalb Danke für Deine Geduld. Hab bisher in anderen Foren nicht so gute Erfahrungen gemacht.

                        Also! Ich werde erstmal weiter knobeln, knobeln, knobeln ... und auf Deine Antwort warten.

                        MfG coastbike

                        Comment


                        • #13
                          Hallo coastbike,

                          ich hoffe ich habs jetzt geschnallt und kann eine funktionierende Lösung präsentieren. (Diesmal hab ich Code geschrieben den ich getestet habe )

                          Folgende Lösung:
                          1. per SQL wird für jedes Objekt in db_gastgeber mittels OUTER JOIN folgendes Ermittelt:
                          - der Vortag vom ersten gebuchten Tag - first_date
                          - der Folgetag vom letzten gebuchten Tag - last_date
                          - der Folgetag vom letzten gebuchten Tag der ersten Buchung - new_first
                          - der Vortag vom ersten gebuchten Tag der letzten Buchung - new_last
                          - die Anzahl der Belegungen im Zeitfenster - anz
                          - die Gesamtzahl der gebuchten Tage im Zeitfenster - tage_i
                          - die Anzahl der freien Tage zwischen first_date und last_date - tage_f
                          - die Anzahl der freien Tage am Anfang des Zeitfenster - tage_b
                          - die Anzahl der freien Tage am Ende des Zeitfenster - tage_e

                          2. Für jeden gefunden DS wird geprüft:
                          - ist anz = 0, dann gibt es keine Buchung für das Objekt und das gesamte Zeitfenster ist frei
                          - ist tage_b >= Reisedauer, dann ist am Anfang was frei
                          - ist tage_e >= Reisedauer, dann ist am Ende was frei
                          - ist anz = 2 und tage_f >= Reisedauer, dann gibt es bei zwei Buchungen einen freien Zeitraum dazwischen
                          - gibt es mehr als zwei Buchungen im Zeitfenster wird die Abfrage rekursiv mit new_first und new_last als neuem Zeitfenster aufgerufen

                          Und damit das Ganze nicht so trocken ist, hab ich diesmal ein komplettes Script angehängt

                          Gruß Falk
                          Attached Files
                          Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

                          Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

                          Comment


                          • #14
                            Hallo Falk,

                            Kann ein wenig dauern
                            Wie sieht das aus, wenn es bei Dir schnell gehen muß? Der Rechner hat mir grad den Eingang gemeldet. Werde nach der Arbeit mich bei machen und Dein Script studieren.

                            Wie gesagt, erstmal Danke.

                            Ich melde mich!

                            MfG coastbike

                            Comment


                            • #15
                              Hallo Falk!

                              Nun habe ich mich mit Deinem Script beschäftigt. Sind ja für mich ein paar neue einfache Sachen drin, die ich zwar auch gelöst hätte, aber auf komplizierteren Wege. Eins macht Dein Script nicht. Es zeigt nicht die Objekte an, die das Zeitfenster nicht berühren, sprich, keine Buchung in dem Zeitfenster haben. Du hast es zwar definiert
                              PHP Code:
                              // greift der outer join? d.h. es gibt keine Buchungen ...
                                      
                              if ($row['anz'] == 0)
                                        
                              // ...dann ist das gesamte Zeitfenster für das Objekt frei!
                                        
                              $pResult[] = array(
                                          
                              'obj_nr' => $row['obj_nr'],
                                          
                              'free'   => "$pVon - $pBis"
                                        
                              ); 
                              , aber er bringt es nicht. Es sei denn, die Buchungen berühren Anfang oder Ende des Zeitfensters. Des weiteren habe ich, da Abreise und Anreise im gleichen Objekt möglich ist, die Vortragwerte auf 0 gesetzt.
                              PHP Code:
                              $sql =
                                   
                              "SELECT DATE_ADD(min(cc.von), INTERVAL 0 DAY) as first_date,
                                      DATE_ADD(max(cc.bis), INTERVAL 0 DAY) as last_date,
                                      DATE_ADD(min(cc.bis), INTERVAL 0 DAY) as new_first,
                                      DATE_ADD(max(cc.von), INTERVAL 0 DAY) as new_last, 
                              Ich werde Dir mal eine abgespeckte Objektdatei und eine Beispiel-Belegungsdatei anhängen zum ausprobieren.

                              Gruss coastbike
                              Attached Files
                              Zuletzt editiert von coastbike; 09.05.2007, 14:13. Reason: Erweiterung des Inhaltes

                              Comment

                              Working...
                              X