[gelöst] Selektions anhand fehlender Datensätze zwischen zwei Datumswerten

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • [gelöst] Selektions anhand fehlender Datensätze zwischen zwei Datumswerten

    Hallo,

    seit gestern sitze ich an einer eigentlich einfachen Abfrage, ohne sie auf die Reihe zu kriegen. Es geht um die Selektion von Datensätzen, zu denen in der verknüpften Tabelle keine Einträge enthalten sind, die sich innerhalb eines bestimmtes Zeitraums (Datum) befinden.

    Es gibt zwei (relevante) Tabellen:

    tbl_objects:
    obj_id (PK)

    tbl_objects_in_use:
    use_id (PK)
    obj_id (FK)
    start_date (datetime)
    end_date (datetime)

    In der Tabelle tbl_objects befinden sich irgendwelche Einträge irgendwelcher Gegenstände. Diese Gegenstände können zur selben Zeit nur einmal benutzt werden, also beginnend mit Datum x und endend mit Datum y. Wird ein Objekt genutzt oder eine Nutzung in der Zukunft geplant, so erfolgt ein Eintrag in der Tabelle tbl_objects_in_use mit den beiden Daten (start_date und end_date).

    Ich benötige nun eine Abfrage, die mir alle Objekte liefert, die innerhalb eines gegebenen Zeitraumes nicht benutzt werden.

    Beispiel:

    Objekt 1 wird benutzt:
    vom 22.10.2009 bis zum 29.10.2009
    vom 02.11.2009 bis zum 12.10.2009
    vom 28.11.2009 bis zum 12.12.2009

    Objekt 2 wird benutzt:
    vom 24.10.2009 bis zum 28.10.2009
    vom 29.10.2009 bis zum 15.11.2009

    Objekt 3 wird benutzt:
    vom 26.11.2009 bis zum 27.11.2009

    Und nun möchte ich alle Objekte selektieren, die vom 14.11.2009 bis zum 27.11.2009 nicht benutzt werden. In diesem Beispiel wäre das nur Objekt 1.

    Aus meiner (offensichtlich falschen) einzigen logischen Lösungsmöglichkeit dreht sich alles um eine Abfrage, die der folgenden immer ähnlich sind. Brauchbare Daten liefert sie jedoch bedauerlicherweise nicht. Leider erschließt sich mir auch nicht, wo der Fehler ist.

    Code:
    SELECT
    	obj.obj_id
    FROM
    	tbl_objects obj
    LEFT JOIN
    	tbl_objects_in_use use
    ON
    	obj.obj_id = use.obj_id
    WHERE
    (
    	use.start_date < '2009-10-16 07:30:00'
    OR
    	use.start_date > '2009-10-17 07:30:00'
    OR
    	use.use_id IS NULL
    )
    AND (
    	use.end_date < '2009-10-16 07:30:00'
    OR
    	use.end_date > '2009-10-17 07:30:00'
    OR
    	use.use_id IS NULL
    )
    GROUP BY
    	obj.obj_id
    Irgendwo muss ich einen gewaltigen Denkfehler haben, denn an sich klingt die Problematik, etwas zu selektieren, das zwischen zwei Daten keine verknüpften Einträge enhält, ja gar nicht so kompliziert ...

    Hat jemand eine Idee?

    pb

  • #2
    Hallo,

    deine Zeitvergleiche in der Where-Klausel sind falsch:

    Code:
    (
    	[B]use.start_date < '2009-10-16 07:30:00'[/B]
    OR
    	[I]use.start_date > '2009-10-17 07:30:00'[/I]
    OR
    	use.use_id IS NULL
    )
    AND (
    	[I]use.end_date < '2009-10-16 07:30:00'[/I]
    OR
    	[B]use.end_date > '2009-10-17 07:30:00'[/B]
    OR
    	use.use_id IS NULL
    )
    Wenn die fett markierten beide zutreffen (and) ist die Bedingung erfüllt, obwohl die Gegenstände schon vor dem ausgewählten Zeitraum in Benutzung waren und es nach Ende des Zeitraums immer noch sein werden.

    Die kursiv markierten matchen genau anders herum. Deine Bedingung trifft also immer zu, soweit ich das überblicke.

    Edit: versuch's mal damit:

    Code:
    SELECT obj.obj_id
    FROM tbl_objects as obj
    LEFT JOIN tbl_objects_in_use as use using(obj_id)
    where use.use_id is null
    	or use.start_date > ENDE_ZEITRAUM
    	or use.end_date < ANFANG_ZEITRAUM
    GROUP BY obj.obj_id
    Gruß,

    Amica
    Zuletzt geändert von AmicaNoctis; 20.10.2009, 11:42.
    [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
    Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
    Super, danke!
    [/COLOR]

    Kommentar


    • #3
      Vielen Dank für den Versuch, Amica.

      Leider klappt auch das nicht. Ich hatte getrennte Bedingungen, um Überlappungen erkennen zu können. Also z. B. belegter Zeitraum von 4 bis 9, gesuchter Zeitraum von 2 bis 5. Dann wäre das Objekt zwar am 2. und 3. frei, am 4. und 5. nicht mehr.

      Ich habe mal einen Dump beider Tabellen mit halbwegs realistischen Daten angehängt. Falls es jemand versuchen möchte, gerne

      Für dieses Beispiel gelten die Suchdaten:

      Start: 17.10.2009
      Ende: 23.10.2009

      Logisch richtige Ergebnisse müss(t)en sein:

      Objekt Id 3
      Objekt Id 6

      Mit Deiner (Amicas) Lösung wird auch der Datensatz Id 1 erfasst, was jedoch falsch ist, da dieser u. a. vom 19.10. bis zum 24.10. benutz wird, sodass er am 23.10. keineswegs zur Verfügung stehen kann, ebenso nicht am 24.10.

      Wie ich es drehe und wende, es kommen entweder belegte Objekte heraus oder freie werden unterschlagen. Ich hasse Daten.

      Und hier noch die angepasste Abfrage:
      Code:
      SELECT obj.obj_id
      FROM tbl_objects as obj
      LEFT JOIN tbl_objects_in_use as used using(obj_id)
      where (used.use_id is null
      	or used.start_date > '2009-10-23 10:10:10'
      	or used.end_date < '2009-10-17 10:10:10')
      and
      	obj.rentable = 1
      GROUP BY obj.obj_id
      pb
      Angehängte Dateien

      Kommentar


      • #4
        Das versteh ich nicht, warum Datensatz 1 bei dir mit im Ergebnis war. Du hast nicht zufällig irgendwo Start und Ende verwechselt. Bitte poste mal das konkrete Statement mit den eingesetzten Werten und die Ergebnismenge (bitte gleich mit den zugehörigen Datumsangaben dahinter).

        Achso, nee. Alles klar. Du brauchst dafür einen Negativ-Left-Join. Die zeitlichen Bedingungen müssen dabei umgekehrt als ON-Klausel zum Join und die Where-Klausel setzt du auf use.use_id is null.
        Zuletzt geändert von AmicaNoctis; 20.10.2009, 12:51.
        [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
        Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
        Super, danke!
        [/COLOR]

        Kommentar


        • #5
          So?:
          Code:
          select obj.obj_id
          from tbl_objects as obj
          left join tbl_objects_in_use as use
          	on use.obj_id = obj.obj_id
          		and use.start_date < ENDE_ZEITRAUM
          		and use.end_date > ANFANG_ZEITRAUM
          where use.use_id is null
          	and obj.rentable = 1
          group by obj.obj_id
          [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
          Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
          Super, danke!
          [/COLOR]

          Kommentar


          • #6
            Du tippst anscheinend schneller als ich denke. Kaum hatte ich in Worte gefasst, wie ich Dir das Fehlverhalten erklären könnte, schon hattest Du die Frage revidiert.

            Die Verlagerung der Bedingungen in die Verknüpfung und die abschließende Filterung funktioniert. Auch nach Überführung in die eigentlichen Abfragen mit den Realdaten scheint die Selektion zu funktionieren, soweit ich das überblicken kann. (Es ist wahrlich zermürbend, überlappende Daten zu vergleichen.)

            An dieser Stelle also herzlichen Dank für Deine Zeit und Hilfe.

            Solltest Du meiner noch nicht überdrüssig sein sowie Zeit und Laune haben, könntest Du mir vielleicht noch erklären, was ein "Negativer (Left) Join" ist. Hiervon hatte ich bis vorhin noch nie etwas gehört und Dein Verweis in zweien Deiner anderen Beiträge hier erschließt mir leider auch nicht, wo denn der Unterschied zwischen einem negativen und einem, ähm, positiven(?) Join ist.

            pb

            Kommentar


            • #7
              Beim negativen Left Join versucht man mit on die rechte Tabelle auf null zu bekommen, damit man mit where rechts.id is null alle Datensätze aus der linken Tabelle bekommt, für die es rechts keine Entsprechung gibt. In deinem Fall alle Gegenstände für die kein Ausleihzeitraum existiert, der in den Anfragezeitraum hineinfällt. Sobald es auch nur einen gäbe, wäre die rechte Seite nicht mehr null. Das war das Problem bei meiner ersten Variante. Die hat alle Gegenstände gefunden, für die es mindestens einen Ausleihzeitraum gab, der nicht im Anfragezeitraum war. Das sagte aber nichts darüber aus, ob es nicht noch eine andere Ausleihe gibt, die dem im Wege steht.

              Tut mir leid, ich kann's grad nicht besser erklären.

              Normalerweise machen viele das mit korrelierten Unterabfragen (/Subqueries/Subselects) wie not in oder not exists, was aber aus Performancegründen nicht so empfehlenswert ist.
              Zuletzt geändert von AmicaNoctis; 20.10.2009, 14:43.
              [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
              Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
              Super, danke!
              [/COLOR]

              Kommentar


              • #8
                Die Erklärung war hinreichend und verständlich. Dankeschön

                Kommentar

                Lädt...
                X