Rolf b: Problem mit MySQL-Abfrage

Beitrag lesen

Hallo,

bin auch perplex. Ich arbeite hauptsächlich mit MS SQL, das ist dagegen ja das reinste Sparta. Und PERIOD_ADD ist dazu noch recht gutmütig, es akzeptiert Zahlen wie Strings und für die Dauer wird 5, '05' und ' 5' akzeptiert. PERIOD_ADD(201613, 5) ergibt 201706, das ist ein guter Fallback für einen 'falschen' Monat. Diese Gutmütigkeit geht natürlich auf Kosten der Geschwindigkeit.

Die Gutmütigkeit endet aber, wenn du für den 1. Parameter von PERIOD_ADD nicht exakt das Format einhältst. PERIOD_ADD(20161, 5) oder PERIOD_ADD('20161', 5) ergibt 20606, und PERIOD_ADD('2016 1', 5) ergibt 202109. Hier musst Du also auf deine DB achten, dass sie korrekte Werte enthält.

So. Und nun zu den echten Problemen.

  1. Je nachdem, was Du haben willst, hat Deine Abfrage das klassische "einen daneben" Problem. Meint: Wenn die Periode in 201604 beginnt und 2 Monate dauert, dann liefert PERIOD_ADD 201606. April bis Juni sind 3 Monate! Du musst also das Ergebnis des PERION_ADD als "erster Monat der nicht mehr im Intervall ist" interpretieren. Das passt aber nicht mit dem between-Test zusammen.

  2. Du findest nicht alles.

    Annahme: in der Datenbank steht: Jahr=2016, Monat=01, Dauer=12. Dein Beginn ist 201604, dein Ende ist 201609. D.h. dein Intervall in der Datenbank beginnt vor $beginn und endet nach $ende. Deine Query wird das nicht finden. Wenn man deine Anforderung wörtlich nimmt: "Innerhalb eines Zeitraums", dann ist das ok. Aber ich befürchte, dass Du diesen Fall als Treffer haben willst.

    Willst Du ihn haben, dann verwende die unten gezeigte Abfrage. Ob Du mit < oder <= arbeiten musst, bzw. mit > oder >=, hängt von deinen Anforderungen ab. Stelle Dir diese Fragen:

    • Links vom AND: Ist ein Datenbanksatz 201604 (mit beliebiger Dauer) noch ein Treffer, wenn $ende = 201604? Ja: verwende <=, nein: verwende <
    • Rechts vom AND: Ist ein Datenbanksatz 201604 mit Dauer 01 ein Treffer, wenn $beginn = 201605? Ja: verwende >=, Nein: verwende >
SELECT *
FROM tabelle
WHERE (concat(jahr,monat) < '$ende') AND (period_add(concat(jahr,monat),dauer) > '$beginn')

Die Entscheidungen zu </<= und >/>= lösen automatisch auch das mögliche "eins daneben" Problem.

Gruß Rolf