MYSQL Abfrageergbnis weiterverarbeiten Datum-Problem

#1
Hallo,
ich versuche jetzt seit Wochen verzweifelt eine Lösung für mein Problem zu finden..
Ich habe in meiner Datenbank eine Tabelle "post_meta". In dieser befinden sich 4 Spalten. in einer Spalte befinden sich Angaben wie Datum, Name, etc. Ich schaffe es die gewünschten Daten zu Filtern und erhalte im Grunde schon ein zufriedenstellendes Ergebnis. ABER:
Wie kann ich aus diesem Ergebnis weiter Filtern? Sprich ich bekomme im Moment den Kundennamen, Kundenkontakt und ein Erinnerungsdatum. Ich möchte eine Email mit den entsprechenden Daten ausgehend vom Erinnerungsdatum - 100 Tage. Leider kann ich es nicht weiter filtern.

Hier mal einer meiner vielen Ansätze:
PHP:
$sql= "meta_value, post_id FROM di0n8s_postmeta WHERE meta_key='name' OR meta_key='kontakt' OR meta_key='start-datum' OR meta_key='befuellung-neu' ORDER BY post_id";
$suchdatum = new DateTime("-100 days");
echo $suchdatum->format("d-m-Y");

Nur wie bekomme ich das kombiniert oder muss ich mit create temporary table arbeiten?

Auch das war ein Ansatz:
PHP:
$suchdatum = new DateTime("-100 days");
echo $suchdatum->format("d-m-Y"); (Ergebnis: 16-08-2016 - wäre ja richtig in der Formatierung)
$query = "SELECT meta_value, post_id FROM wb16_postmeta WHERE meta_key='start-datum'AND DATEDIFF(NOW(), 'post_date') > 11";

Funktioniert leider auch nicht.. Wo ist denn nur mein Denkfehler?

Hier meine Tabelle - ein Ausschnitt..

tabelle.jpg

Wenn ich versuche das Ganze gleich nach Datum zu durchsuchen:

PHP:
$suchdatum = new DateTime("-100 days");
echo $suchdatum->format("d-m-Y");
$query = "SELECT meta_value, post_id FROM wb16_postmeta WHERE meta_key='start-datum' LIKE '$suchdatum'";

erhalte ich folgende Fehlermeldung:
Catchable fatal error: Object of class DateTime could not be converted to string

Was ja logisch ist, da das Feld nicht als Datum formatiert ist..

Ich hoffe ich konnte mich einigermaßen Verständlich ausdrücken..


Über jede Hilfe bin ich dankbar. Google hab ich auch schon befragt, aber mir fehlt einfach der Ansatz..

Gruß,
Tanja
 
#2
Hi

Etwas ist mir nicht ganz klar: Das heutige Datum minus 100 Tage muss was genau sein? Gleich wie start-datum, älter als start-datum, ...?

Angenommen "gleich wie" ist das Ziel, und der Wert in der DB ist wirklich immer im richtigen Format:
SQL:
SELECT meta_value, post_id FROM wb16_postmeta WHERE meta_key='start-datum'
AND DATEDIFF(CURDATE(),STR_TO_DATE(meta_value,'%d-%m-%Y'))=100
 
#3
Ich nehme nur dein letzter Versuch. sonst wirds unübersichtlich
PHP:
$query = "SELECT meta_value, post_id FROM wb16_postmeta WHERE meta_key='start-datum' LIKE '$suchdatum'";
Code:
WHERE feld1 = 'value2' LIKE 'value2'
Das ist ein komisches WHERE. So müsste es sein
WHERE feld1 = 'value2' AND feld2 LIKE 'value2'
In deinem Fall auch kein LIKE

Dann noch den String ausgeben und nicht die Klasse
PHP:
$dateString = $suchdatum->format("d-m-Y");
$query = "SELECT meta_value, post_id FROM wb16_postmeta WHERE meta_key='start-datum' and meta_value = '$dateString'";

Zudem ist die Spalte meta_value auch nicht als Datum sondern als String hitnerlegt. In deinem Fall gegen die SQL-Regel Y-m-d hast du d-m-Y. Du musst einfach noch mit STR_TO_DATE ein Datum daraus machen. Das ist wichtig, wenn man damit rechnen will.
SQL:
STR_TO_DATE('24-11-2016', '%d-%m-%Y')
Also drehen wir bereits bei dem $suchdatum->format() das Fromat um.
Zudem den Wert aus der Tabelle wie oben erwähnt in ein Datum wandeln.

Jetzt willst du alle die die Datum-100 Tage
PHP:
$dateString = $suchdatum->format("Y-m-d");
$query = "
    SELECT
        meta_value,
        post_id
    FROM wb16_postmeta
    WHERE
        meta_key='start-datum'
        AND STR_TO_DATE(meta_value, '%d-%m-%Y') >= DATE_SUB('$dateString', INTERVAL 100 DAY)"
Das ganze ist natürlich ungetestet und ohne Gewehr
 
#4
Vielen Dank ersteinmal!
Zum Verständnis:
@sheel
Also das Problem ist ich habe eine Datenbank mit ca. 1200 Kundendaten. Jeder Kunde soll per mail erinnert werden. Dazu brauche ich zwei Abfragen. Einmal nach 6 Monaten und einmal nach 12 Monaten rückwärts gerechnet von start-datum. Das Start datum ist eigentlich nur das Eingabedatum wann der Kunde eingetragen wurde. Also der Kunde soll in 6 bzw. 12 Monaten erinnert werden. Ich habe zum probieren erstmal minus 100 Tage (-100) genommen.
Das ganze ist in WordPress verpackt und leider ist das Datum nicht als Datum in der Tabelle eingetragen... da ist gar keine Angabe. Und wenn ich versuche es zu ändern zerschießt es mir meinen Eintrag.

Hoffe das ist verständlich...
 
#5
@Yaslaw
Vielen vielen Dank! Das probiere ich jetzt gleich mal aus.
Aber, was kann ich denn tun wenn ich den Eintrag nicht als Datum ausgeben bzw. ändern kann?
 
#6
Aber, was kann ich denn tun wenn ich den Eintrag nicht als Datum ausgeben bzw. ändern kann?
Steht doch. STR_TO_DATE() macht aus einem String ein Datum. Ohne Datum kannst du keine Datumsrechnungen durchführen.
 
#7
Hallo Yaslaw,

vielen Dank für Deine Geduld. Ich hab jetzt eine Menge probiert, aber egal wie, ich erhalte immer:

Fatal error: Call to a member function format() on null ...

Der Fehler verweist auf:

PHP:
$dateString = $suchdatum->format("Y-m-d");
Irgendwie funktioniert was mit der Formatierung nicht - aber was? Hast Du eine Idee?

Vielen Dank und viele Grüße
 
#8
Hm. Bei mir funktioniert der Test: Test bei phpfiddle
PHP:
<?php
$suchdatum = new DateTime("-100 days");
echo $suchdatum->format("Y-m-d");
?>
Die Fehlermeldung besagt eigentlich, das $suchdatum nicht definiert wurde. In einem alten Post hast du des definiert. Aber wie es im aktuellen Code ist, sehe ich anhand deines Einzeilers nicht.
 
#9
Ja, wer lesen kann.. Ich hab ein Semikolon vergessen.. Und dafür so vierl versucht. Tut mir leid, hätte ich meinen Code besser gelesen hätte es mir gleich auffallen müssen.

Vielen vielen Dank. Hab Dank Dir eine Menge dazu gelernt!
 
#10
Ich hätte bitte doch noch eine Frage:

Meine Abfrage sieht jetzt so aus:
PHP:
$suchdatum = new DateTime("-100 days");
echo $suchdatum->format("Y-m-d");
$dateString = $suchdatum->format("Y-m-d");
$sql = "CREATE VIEW auswahl_view AS
SELECT meta_value, meta_key, post_id FROM wb16_postmeta
WHERE
       meta_key='name' OR meta_key='kontakt' OR meta_key='start-datum' OR meta_value='conditioner'";
$result = mysql_query($sql) or die("Anfrage fehlgeschlagen: " . mysql_error());
$query = "
   SELECT
       meta_value,
       post_id
    FROM auswahl_view
   WHERE
       (meta_key='start-datum'
       AND (DATEDIFF(CURDATE(), STR_TO_DATE(meta_value, '%d-%m-%Y')) = 350))";
$result = mysql_query($query) or die("Anfrage fehlgeschlagen: " . mysql_error());
Die Ansicht 'auswahl_view' beinhaltet schon mal die Vorauswahl. Wie schaffe ich es jetzt, dass ich nicht nur das Datum und die ID erhalte sondern auch noch Angaben wie Name und Kontakt?

Oder ist mein Ansatz falsch? Verschachtelte Abfragen sind echt nicht so einfach.. Ich dachte auch schon an CASE oder eine IF ELSE Abfrage..
 
#11
Durch das Erzeugen der VIEW habe ich schon eine Vorauswahl getroffen. Die Datumsabfrage klappt auch, aber mein Ergebnis sieht so aus:
29-11-2015 2318
29-11-2015 2324

Ist schon die Hälfte der Miete.. Aber ich brauche noch die passenden Informationen zur ID. Gibt es da keine Möglichkeit? Leider kann man ja nicht mehr ANDs dazuschreiben.. Sonst wäre es ja einfach.. ;-)

Ich brauch nur einen Ansatz. Oder einen Schubs in die richtige Richtung. Bitte!
 
#12
Jedes mal eine View erstellen -> Falscher Ansatz.

Alles in einem. Schwer ist es nicht
SQL:
select distinct 
	pm.*
from 
	wb16_postmeta as pm,
	(
		select 
			post_id, 
			str_to_date(meta_value, '%d-%m-%Y') AS start_date
		from wb16_postmeta 
		where meta_key='start-datum'
	) as sd
where 
	pm.post_id = sd.post_id
	and datediff(curdate(), sd.start_date) = 350
Bist du sicher, dass es =350 sein muss? Also nur was genau vor 350 Tagen war?

Ergänzt um deinen weiteren Filter der View
SQL:
select distinct 
	pm.*
from 
	wb16_postmeta as pm,
	(
		select 
			post_id, 
			str_to_date(meta_value, '%d-%m-%Y') AS start_date
		from wb16_postmeta 
		where meta_key='start-datum'
	) as sd
where 
	pm.post_id = sd.post_id
	and datediff(curdate(), sd.start_date) < 350
	and (
		pm.meta_key in ('name','kontakt','start-datum')
		OR pm.meta_value='conditioner'
	)
 
#13
Das mit dem VIEW hab ich über
PHP:
$sql = "CREATE OR REPLACE VIEW auswahl_view AS
SELECT meta_value, meta_key, post_id FROM wb16_postmeta
WHERE
       meta_key='name' OR meta_key='kontakt' OR meta_key='start-datum' OR meta_value='conditioner'";
gedacht zu lösen..
Das Problem ist allerdings, dass ich eigentlich kein OR meta_value='conditioner' bräuchte sondern ein AND. Das heißt ich wollte erst eine Abfrage machen bei dem alle Datensätze die Meta_value='conditioner' haben aufgelistet werden und danach nach Datum gefiltert werden. Funktioniert nur leider nicht. Das Script soll dann 1 x täglich als cronjob laufen..

Ich hab das mal ausprobiert, aber jetzt funktioniert das Selektieren vom Datum nicht mehr? Er gibt mir jetzt zwar alle Informationen aber ohne Datums-Selektion.
 
#14
Eine View, die erstellt man einmal und dann ist die da. Die ist Bestandteil des Programms.

Da du nur sehr spezifische Felder auswählst, würde ich eine Kreuztabelle erstellen und diese nach dem Gruppieren mit HAVING (ist wie ein WHERE, wird aber auf das gruppierte Ergebnis angewendet) ausfiltern

SQL:
select
    post_id,
    max(if(meta_key = 'name', meta_value, '')) AS name,
    max(if(meta_key = 'kontakt', meta_value, '')) AS kontakt,
    max(if(meta_key = 'start-datum', str_to_date(meta_value, '%d-%m-%Y'), '')) AS start_date,
    max(meta_value = 'conditioner') AS is_conditioner
from wb16_postmeta
group by post_id
having
    is_conditioner
    and datediff(curdate(), start_date) = 350
Das ergibt dann so etwas:
Code:
post_id | name  | kontakt | start_date | is_conditioner
--------|-------|---------|------------|---------------
      1 | meier |         | 2015-12-31 | 1
 
#16
Vorsicht. Es heisst zwar Kreuztabelle oder Pivottabelle. Aber es ist ein Query. Die Daten sollten nicht so gespeichert werden. Damit kannst du einfach relativ elegant die wesentlichen Werte auslesen und konvertieren.
Hier lohnt es sich ev. die Kreuztabelle (ohne HAVING) als View zu speichern. Aber einmalig, nicht bei jedem lauf.