jakicoll
Goto Top

Heinz die Banner anzeigen die er noch nicht gesehen hat (JOIN?)

Hey!
Also folgendes:
Ich habe in meinem MySQL zwei InnoDB-Tabelle:
Tabelle Nummer 1: Banner:
ID | Name
1 |Foo
2 |Bar
3 |FooBar
Tabelle Nummer 2: Reload
User | B_ID | (DATETIME) Until
Heinz | 1 | 2009-02-27 20:15:00
Heinz |2 |2008-01-01 19:30:00

Banner:Reload ist logischerweise 1:m
Gehen wir einfach mal davon aus, dass NOW(); 2009-02-27 19:00:00 ist.
->Heinz ist also für Banner 1 im Reload, sein Reload für Banner 2 ist abgelaufen und für 3 hat er keinen Tupel in der Reload-Tabelle

Wie der Titel schon sagt möchte ich "Heinz" jetzt die Banner anzeigen für die er nicht im Reload ist.
Das heißt:
Es gibt keinen Tupel der Heinz und die BannerID aufweisst, oder der Tupel ist abgelaufen -> TIMEDIFF(NOW(),Reload.Until)>0

Meine Datenbankerfahrung ist zwar eingentlich ganz ordentlich, aber ich krieg's einfach nicht hin....

Er hatte ich einen OUTER-Join im Verdacht, aber der wollte nicht.
Ein INNER kommt ja nicht in Frage, weil keine 1:1 Beziehung.

PS:
Um euch Nachschlagarbeit zu TIMEDIFF zu ersparen:

mysql> SELECT TIMEDIFF('2009-02-27 19:00:00','2009-02-27 18:00:00') AS dif;
+----------+
| dif |
+----------+
| 01:00:00 |
+----------+

Content-Key: 110195

Url: https://administrator.de/contentid/110195

Printed on: April 18, 2024 at 20:04 o'clock

Member: jakicoll
jakicoll Feb 28, 2009 at 08:34:01 (UTC)
Goto Top
Gestern Abend um 23:30 machte es endlich klick bei mir!
Eine mögliche Lösung ist:
Eine Subquery die alle Banner rausucht für die Heinz im Reload ist und mit einem NOT IN in der eigentlichen Query ausgewertet wird:
SELECT `name` FROM `banner`
WHERE `id` NOT ( SELECT `b_id` FROM `reload` WHERE `user`="Heinz" AND TIMEDIFF(NOW(), `until`)<1 )
Limit 1;

Edit: Scheint noch ein Fehler während des Datumsvergleiches drin zu sein!
Wenn ich als Subquery folgendes nehme gehts:
SELECT `id`
FROM `reload`
WHERE `user` = 'Heinz'
AND NOW( ) < `reload` ;


Danke trotzdem!

jakicoll
Member: nxclass
nxclass Feb 28, 2009 at 09:47:59 (UTC)
Goto Top
warum machst du keinen LEFT JOIN und gibst alle Zeilen zurück wo die Werte der 2. Tabelle IS NULL sind ?

(ggf. sprengst Du dein Speicher- und Time- Limit bei der 'NOT IN (SELECT ...) Abfrage)
Member: jakicoll
jakicoll Feb 28, 2009 at 19:15:20 (UTC)
Goto Top
Hmm, das mit dem Speicher hab' ich nicht bedacht.
Da in der Banner-Tabelle meistens nur um die 30-40 Einträge sind ist das kein so großes Problem (oder?)

Das mit dem Left Join würde doch nur Funktionieren wenn es für jeden User zu jedem Banner einen Eintrag in der Reload Tabelle geben würde, der wenn er nicht im Reload ist halt auf NULL steht, aber das wäre bei über 100 aktiven Usern nicht ganz so günstig, da die Kampagnen häufig wechseln und dann für jede Kampagne 100 Tupel in der Reload Tabelle angelegt oder gelöscht werden müssten...

Oder täusche ich mich etwa?

Grüße,

Jakicoll
Member: nxclass
nxclass Mar 01, 2009 at 09:16:52 (UTC)
Goto Top
Das Speicher Problem ist erstmal zweitrangig - Optimierung ist ja immer erst der 2. Schritt - erstmal muss es gehen.

SELECT b.id
FROM
  banner b LEFT JOIN (
    SELECT b_id FROM reload
    WHERE
      DATE_ADD(until, INTERVAL 1 HOUR) < NOW() AND
      user_id = ?
  ) tmp ON b.id = tmp.b_id
WHERE
  tmp.b_id IS NULL;

das sollte gehen - und Du sparst dir dieses 'NOT IN' - meine Erfahrung zeigt das es rel. langsam ist und nur bei Konstanten sinn macht.

Der LEFT JOIN gibt alle Einträge aus der 'banner' Tabelle und nur die Eintrage aus der 'reload' Tabelle zurück die die ON Klausel erfüllen, somit sind bei nicht vorhandenen Einträgen, aus der 'reload' Tabelle' NULL Werte eingetragen.