php-resource



Zurück   PHP-Scripte PHP-Tutorials PHP-Jobs und vieles mehr > Entwicklung > SQL / Datenbanken
 

Login

 
eingeloggt bleiben
star Jetzt registrieren   star Passwort vergessen
 

 

 


SQL / Datenbanken Probleme mit SQL? Hier könnt ihr eure Fragen zu SQL (MySQL, PostgreSQL, MS-SQL und andere ANSI-SQL Server) los werden.

Antwort
 
LinkBack Themen-Optionen Thema bewerten
  #1 (permalink)  
Alt 20-10-2009, 11:26
plastikbaum
 Registrierter Benutzer
Links : Onlinestatus : plastikbaum ist offline
Registriert seit: Aug 2005
Beiträge: 66
plastikbaum ist zur Zeit noch ein unbeschriebenes Blatt
Lightbulb [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
Mit Zitat antworten
  #2 (permalink)  
Alt 20-10-2009, 11:37
AmicaNoctis
  Moderatorin
Links : Onlinestatus : AmicaNoctis ist offline
Registriert seit: Jul 2009
Beiträge: 5.709
Blog-Einträge: 9
AmicaNoctis sorgt für eine eindrucksvolle AtmosphäreAmicaNoctis sorgt für eine eindrucksvolle Atmosphäre
Standard

Hallo,

deine Zeitvergleiche in der Where-Klausel sind falsch:

Code:
(
	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
)
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

Geändert von AmicaNoctis (20-10-2009 um 11:42 Uhr)
Mit Zitat antworten
  #3 (permalink)  
Alt 20-10-2009, 12:35
plastikbaum
 Registrierter Benutzer
Links : Onlinestatus : plastikbaum ist offline
Registriert seit: Aug 2005
Beiträge: 66
plastikbaum ist zur Zeit noch ein unbeschriebenes Blatt
Standard

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
Dateityp: zip dump.zip (1,4 KB, 1x aufgerufen)
Mit Zitat antworten
  #4 (permalink)  
Alt 20-10-2009, 12:47
AmicaNoctis
  Moderatorin
Links : Onlinestatus : AmicaNoctis ist offline
Registriert seit: Jul 2009
Beiträge: 5.709
Blog-Einträge: 9
AmicaNoctis sorgt für eine eindrucksvolle AtmosphäreAmicaNoctis sorgt für eine eindrucksvolle Atmosphäre
Standard

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.

Geändert von AmicaNoctis (20-10-2009 um 12:51 Uhr)
Mit Zitat antworten
  #5 (permalink)  
Alt 20-10-2009, 12:57
AmicaNoctis
  Moderatorin
Links : Onlinestatus : AmicaNoctis ist offline
Registriert seit: Jul 2009
Beiträge: 5.709
Blog-Einträge: 9
AmicaNoctis sorgt für eine eindrucksvolle AtmosphäreAmicaNoctis sorgt für eine eindrucksvolle Atmosphäre
Standard

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
Mit Zitat antworten
  #6 (permalink)  
Alt 20-10-2009, 14:01
plastikbaum
 Registrierter Benutzer
Links : Onlinestatus : plastikbaum ist offline
Registriert seit: Aug 2005
Beiträge: 66
plastikbaum ist zur Zeit noch ein unbeschriebenes Blatt
Standard

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
Mit Zitat antworten
  #7 (permalink)  
Alt 20-10-2009, 14:11
AmicaNoctis
  Moderatorin
Links : Onlinestatus : AmicaNoctis ist offline
Registriert seit: Jul 2009
Beiträge: 5.709
Blog-Einträge: 9
AmicaNoctis sorgt für eine eindrucksvolle AtmosphäreAmicaNoctis sorgt für eine eindrucksvolle Atmosphäre
Standard

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.

Geändert von AmicaNoctis (20-10-2009 um 14:43 Uhr)
Mit Zitat antworten
  #8 (permalink)  
Alt 20-10-2009, 14:41
plastikbaum
 Registrierter Benutzer
Links : Onlinestatus : plastikbaum ist offline
Registriert seit: Aug 2005
Beiträge: 66
plastikbaum ist zur Zeit noch ein unbeschriebenes Blatt
Standard

Die Erklärung war hinreichend und verständlich. Dankeschön :)
Mit Zitat antworten
Antwort

Lesezeichen


Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)
 

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Nur Datensätze anzeigen, wenn heute zwischen zwei angegebenen Daten liegt DerUnsympath SQL / Datenbanken 11 24-02-2009 15:41
Bezug zwischen zwei Programmen Someday SQL / Datenbanken 0 20-02-2008 14:09
Datum zwischen zwei Datumsangaben Wannabe SQL / Datenbanken 2 03-12-2005 18:06
Zwischen zwei Textstellen auslesen ProfOli PHP Developer Forum 2 29-08-2004 23:34
PHP - Entfernung zwischen zwei PLZ DarkWanderer Apps und PHP Script Gesuche 1 21-06-2004 15:56

Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an


PHP News

ebiz-trader 7.5.0 mit PHP7 Unterstützung veröffentlicht
ebiz-trader 7.5.0 mit PHP7 Unterstützung veröffentlichtDie bekannte Marktplatzsoftware ebiz-trader ist in der Version 7.5.0 veröffentlicht worden.

28.05.2018 | Berni

Wissensbestand in Unternehmen
Wissensbestand in UnternehmenLebenslanges Lernen und Weiterbilden sichert Wissensbestand in Unternehmen

25.05.2018 | Berni


 

Aktuelle PHP Scripte

ebiz-trader 6.0 - Das professionelle PHP Marktplatz Script ansehen ebiz-trader 6.0 - Das professionelle PHP Marktplatz Script

Mit unserer Lösungen können Sie nahezu jeden B2B / B2C Marktplatz betreiben den Sie sich vorstellen können. Ganz egal ob Sie einen Automarktplatz, Immobilenportal oder einfach einen Anzeigenmarkt betreiben möchten. Mit ebiz-trader können Sie Ihre Anforder

11.10.2018 Berni | Kategorie: PHP/ Anzeigenmarkt
PHP Server Monitor

PHP Server Monitor ist ein Skript, das prüft, ob Ihre Websites und Server betriebsbereit sind.

11.09.2018 Berni | Kategorie: PHP/ Security
PHP WEB STATISTIK ansehen PHP WEB STATISTIK

Die PHP Web Statistik bietet Ihnen ein einfach zu konfigurierendes Script zur Aufzeichnung und grafischen und textuellen Auswertung der Besuchern Ihrer Webseite. Folgende zeitlichen Module sind verfügbar: Jahr, Monat, Tag, Wochentag, Stunde Folgende son

28.08.2018 phpwebstat | Kategorie: PHP/ Counter
 Alle PHP Scripte anzeigen

Alle Zeitangaben in WEZ +2. Es ist jetzt 18:52 Uhr.