Guten Morgen, Jack -
fangen wir einfach einmal an:
Code: Alles auswählen
SELECT * FROM artikel LEFT JOIN prijs ON ar_id = ap_ar_id
Dies bringt eine Verbindung aller JOINbaren Sätze.
Für einen kleinen Test:
Code: Alles auswählen
mysql> create table artikel (ar_id int, ar_name char(20), ar_ean int);
Query OK, 0 rows affected (0.16 sec)
mysql> create table prijs (ap_ar_id int, ap_date date, ap_prijs decimal(7,2));
Query OK, 0 rows affected (0.08 sec)
mysql> insert into artikel values(1, 'Petersilie', 12345), (2, 'Graubrot', 56789), (3, 'Schaufel', 90123);
Query OK, 3 rows affected (0.03 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> insert into prijs values(1, '2014-12-01', 1.22), (1, '2014-12-05', 1.25);
Query OK, 2 rows affected (0.05 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> insert into prijs values(2, '2014-12-08', 2.50), (3, '2014-11-30', 11.11);
Query OK, 2 rows affected (0.05 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> insert into prijs values(3, '2014-12-07', 11.20), (4, '2013-01-01', 9.99);
Query OK, 2 rows affected (0.05 sec)
Records: 2 Duplicates: 0 Warnings: 0
Code: Alles auswählen
artikel:
1 | Petersilie | 12345
2 | Graubrot | 56789
3 | Schaufel | 90123
Code: Alles auswählen
prijs:
1 | 20141201 | 1.22
1 | 20141205 | 1.25
2 | 20141208 | 2.50
3 | 20141130 | 11.11
3 | 20141207 | 11.20
4 | 20130101 | 9.99
Code: Alles auswählen
Ergebnis:
1 | Petersilie | 12345 | 1 | 20141201 | 1.22
1 | Petersilie | 12345 | 1 | 20141205 | 1.25 <=
2 | Graubrot | 56789 | 2 | 20141208 | 2.50 <=
3 | Schaufel | 90123 | 3 | 20141130 | 11.11
3 | Schaufel | 90123 | 3 | 20141207 | 11.20 <=
Da es ein LEFT JOIN ist, enthält das Ergebnis alle Sätze aus der links stehenden Datei (artikel), sowie alle Sätze aus der rechts stehenden Datei (prijs), die über ar_id = ap_ar_id zugeordnet werden können.
Du benötigst aber nur die Sätze, die ich mit '<=' gekennzeichnet habe. Da es in prijs mehrere Sätze geben kann, müssen wir das ganze über GROUP und SORT einschränken. Unternehmen wir den ersten Versuch:
Code: Alles auswählen
mysql> select ar_id, ar_name, ar_ean, ap_ar_id, max(ap_date), ap_prijs from artikel left join prijs on ar_id = ap_ar_id
group by ar_id order by ar_id, ap_date;
+-------+------------+--------+----------+--------------+----------+
| ar_id | ar_name | ar_ean | ap_ar_id | max(ap_date) | ap_prijs |
+-------+------------+--------+----------+--------------+----------+
| 1 | Petersilie | 12345 | 1 | 2014-12-05 | 1.22 |
| 2 | Graubrot | 56789 | 2 | 2014-12-08 | 2.50 |
| 3 | Schaufel | 90123 | 3 | 2014-12-07 | 11.11 |
+-------+------------+--------+----------+--------------+----------+
3 rows in set (0.00 sec)
Das sieht zwar schon gut aus, aber es wird immer der erste Preis für einen Artikel aus prijs genommen. Das liegt daran, dass man darauf (leider) keinen Einfluss hat.
Aber wir haben jetzt ein Result Set, das alle Informationen enthält, die wir brauchen, um an das gewünschte Ergebnis zu kommen: wir kennen sowohl ar_id als auch das neueste ap_date.
Ein Result Set kann auch erzeugt werden, wenn ich in einem anderen Result Set nachschaue, welche Sätze in haben will. Die vorhergehende SELECT-Anweisung erzeugt mir dieses Result Set. Ich reduziere die Anweisung auf die beiden Felder ar_id und ap_date und greife auf mein erstes SELECT zurück, filtere aber auf die Sätze, die sich in dem Result Set mit GROUP und SORT finden:
Code: Alles auswählen
mysql> select * from artikel left join prijs on ar_id = ap_ar_id where (ar_id, ap_date) in (select ar_id, max(ap_date) from artikel left join prijs on ar_id = ap_ar_id group by ar_id order by ar_id, ap_date);
+-------+------------+--------+----------+------------+----------+
| ar_id | ar_name | ar_ean | ap_ar_id | ap_date | ap_prijs |
+-------+------------+--------+----------+------------+----------+
| 1 | Petersilie | 12345 | 1 | 2014-12-05 | 1.25 |
| 2 | Graubrot | 56789 | 2 | 2014-12-08 | 2.50 |
| 3 | Schaufel | 90123 | 3 | 2014-12-07 | 11.20 |
+-------+------------+--------+----------+------------+----------+
3 rows in set (0.00 sec)
Beginnen wir mit
Code: Alles auswählen
(select ar_id, max(ap_date) from artikel left join prijs on ar_id = ap_ar_id group by ar_id order by ar_id, ap_date)
Mit diesem SELECT isoliere ich Artikel und Datum.
Und dann fordere ich alle Felder an aus dem LEFT JOIN, wobei ich als Bedingung setze, dass die Sätze (was ar_id und ap_date angeht) durch das in Klammern stehende SELECT ausgewählt wurden.
Dies weist den Server an, für jede Zeile im Result Set zu prüfen, ob die Kombination ar_id und ap_date in dem Result Set steht, das in Klammern steht. Ist das der Fall, wird die Zeile verwendet, gibt es keine Übereinstimmung, wird die Zeile nicht verwendet.
Ich hoffe, ich konnte das einigermassen deutlich erklären.