Richtige SQL Query gesucht

Duergy

Mitglied
Halli Hallo,

Ich habe ein Problem, und zwar geht es um die richtige Query zum auslesen von Werbebannern aus der mysql Datenbank nach Kategorie, größe und priorität.

Wir haben 3 Tabellen

kategorien (kid, kname)
reload(bannerid, ip, reloadsperre_bis)
werbebanner(bannerid, nur_in_den_kategorien, size, prio)

Ein werbebanner kann auch mehreren Kategorien angehören, allerdings bin ich mir noch unklar wie ich die kategoriezuweisungen für die werbebanner in der tabelle "werbebanner" am besten unterbringe.

Die Kategorie-ID (kid) wird überliefert auch die größe.
Wie würde die Query lauten wenn ich folgende

"Zeige mir einen Banner mit der höchsten Priorität und der größe A der in Kategorie B gezeigt werden darf und bei /ip/ nicht im reload ist.
 
kategorien (kid, kname)
reload(bannerid, ip, reloadsperre_bis)
werbebanner(bannerid, nur_in_den_kategorien, size, prio)

Ein werbebanner kann auch mehreren Kategorien angehören, allerdings bin ich mir noch unklar wie ich die kategoriezuweisungen für die werbebanner in der tabelle "werbebanner" am besten unterbringe.
Das Feld „nur_in_den_kategorien“ zeigt schon, dass da etwas nicht ganz in Ordnung ist. Hier besteht eine m:n-Relation zwischen zwei Tabellen, oder auf Deutsch: Ein Werbebanner kann in mehreren Kategorien vorkommen, handkehrum kann eine Kategorie aber auch mehrere Werbebanner enthalten. Und immer wenn du so eine Situation hast, solltest du eine zusätzliche Tabelle einführen, die die beiden miteinander verbindet: einteilung(id, kid, bannerid), in der (natürlich) „kid“ und „bannerid“ Fremdschlüssel auf „kategorien“ bzw. „werbebanner“ sind.

Wenn du das dann hast, können wir uns deinen Query vornehmen. ;)
 
was für einen Nachteil würdest du sehen, wenn ich die Kategorien in einer Spalte in den format "1,2,3,4.." machen würde
 
Der Nachteil ist, dass es sehr schwierig ist (wenn überhaupt Möglich) eine passende Abfrage zu gestalten.
Wenn die Tabellen so aussehen wäre das einfacher und sogar normalisiert:

kategorien (kid, kname)
reload(bannerid, ip, reloadsperre_bis)
werbebanner(bannerid, size, prio)
werbebanner_kategorien(bannerid, kid)
 
Und präventiv schonmal einen entsprechenden Query, für den Fall, dass du die Datenbank wie vorgeschlagen normalisiert hast:

SQL:
SELECT `werbebanner`.`bannerid` FROM `werbebanner`, `einteilung`, `kategorien` WHERE `werbebanner`.`size` = "A" AND `werbebanner`.`bannerid` = `einteilung`.`bannerid` AND `einteilung`.`kid` = `kategorien`.`kid` AND `kategorien`.`kname` = "B" AND [...] ORDER BY `werbebanner`.`prio` DESC LIMIT 1

(Die Tabellennamen kann man vermutlich an der ein oder anderen Stelle noch weglassen – ist bei mir schon länger her mit dem SQL.)

[...] enthält den Teil, den du etwas unklar mit „und bei /ip/ nicht im reload ist“ umschrieben hast. Was genau meinst du? Bezieht sich das auf die Spalte „ip“ oder auf „reloadsperre_bis“?
 
Wie Luckerking schon sagte, gestaltet sich das Auslesen schwierig, wenn du dieses Format wählst.
Natürlich ist es möglich, via PHP die richtigen Daten zu extrahieren.
Bei dem Design einer Applikation sollte aber immer darauf geachtet werden, die Datenbank möglichst korrekt umzusetzen. Die Datenbank ist in Webapplikationen meistens die Basis. Sind hier Designprobleme, dann wird das Entwickeln später nur schwieriger, unübersichtlicher etc, da du ja später eventuell von mehreren Stellen auf die selben Tabellen zugreifen wirst.

Ein Beispiel:
Man könnte sich zum Beispiel vorstellen, dass die Beziehung Kategorie<>Werbebanner später Eigenschaften bekommen könnten.
Ich könnte mir zum Beispiel vorstellen, dass man Prioritäten in Abhängigkeit der Kategorie definieren könnte.
Mit deiner Lösung wäre es schwierig, dies umzusetzen.
Hättest du aber eine Zwischentabelle, könntest du ganz einfach ein weiteres Feld anlegen (prio) um hier die Priorität des Werbebanners in der jeweiligen Kateogorie zu bestimmen.

So sähe ein bessers Tabellendesign aus:

Tabelle Kategorie:
id | name
Tabelle Werbebanner:
id | size | usw...
Tabelle kategorie_werbebanner:
kategorie_id | werbebanner_id | [ZUM BEISPIEL PRIO ALS WEITERES FELD]

Viele Grüße
Johannes
 
Okay ihr habt mich überzeugt *g* werde das nun so realisiseren. vielen dank vorerst. Ich lasse den Thread vorerst noch auf "unerledigt" bis ich es umgesetzt habe.
 
Und präventiv schonmal einen entsprechenden Query, für den Fall, dass du die Datenbank wie vorgeschlagen normalisiert hast:

SQL:
SELECT `werbebanner`.`bannerid` FROM `werbebanner`, `einteilung`, `kategorien` WHERE `werbebanner`.`size` = "A" AND `werbebanner`.`bannerid` = `einteilung`.`bannerid` AND `einteilung`.`kid` = `kategorien`.`kid` AND `kategorien`.`kname` = "B" AND [...] ORDER BY `werbebanner`.`prio` DESC LIMIT 1

(Die Tabellennamen kann man vermutlich an der ein oder anderen Stelle noch weglassen – ist bei mir schon länger her mit dem SQL.)

[...] enthält den Teil, den du etwas unklar mit „und bei /ip/ nicht im reload ist“ umschrieben hast. Was genau meinst du? Bezieht sich das auf die Spalte „ip“ oder auf „reloadsperre_bis“?

Also dein Code funktioniert super, nur fehlt mir jetzt die reloadsperre *duck*

wenn ich es erweitere

SQL:
SELECT `werbebanner`.`bannerid` FROM `werbebanner`, `einteilung`, `kategorien`, `reload` WHERE `werbebanner`.`size` = "A" AND `werbebanner`.`bannerid` = `einteilung`.`bannerid` AND `einteilung`.`kid` = `kategorien`.`kid` AND `kategorien`.`kname` = "B" AND `reload`.`ip` != '$ip' ORDER BY `werbebanner`.`prio` DESC LIMIT 1
bekomme ich kein ergebniss raus

reloads
bannerid | ip | bis*

*= timestamp bis wann der reload gültig ist.

achso und der banner muss noch status=1 haben...
 
Zuletzt bearbeitet:
Tut mir leid, ich blick da überhaupt nicht durch. Vielleicht formulierst du erstmal auf Deutsch, was die Spalten „ip“ und „reloadsperre_bis“ (bzw. jetzt plötzlich „bis“) zu bedeuten haben und was du eigentlich zu verwirklichen gedenkst.

Ausserdem: Wo ist der Status eines Banners gespeichert?
 
ich möchte, das Werbebanner in nur bestimmten kategorien angezeigt werden. z.b. "Autoreifenwerbung" in "Auto & Zubehör"
die reloadsperre_bis habe ich umbenannt auf nur noch bis deswegen heißt die aufeinmal anders
der Status ist neu dazu gekommen in der Tabelle der Werbebanner

Hier jetzt nochmal die ganze Struktur

SQL:
`dls_banner` (
  `bid` int(11) NOT NULL AUTO_INCREMENT,
  `cid` int(11) NOT NULL,
  `bname` varchar(255) NOT NULL,
  `bimg` varchar(255) NOT NULL,
  `bziel` varchar(255) NOT NULL,
  `bmenge_ges` int(11) NOT NULL,
  `bmenge_noch` int(11) NOT NULL,
  `reload` int(11) NOT NULL,
  `prio` int(11) NOT NULL,
  `status` int(11) NOT NULL,
  `size` int(11) NOT NULL,
  PRIMARY KEY (`bid`)
) 

`dls_banner_kategorien` (
  `kid` int(11) NOT NULL,
  `bid` int(11) NOT NULL
)

`dls_client` (
  `cid` int(11) NOT NULL AUTO_INCREMENT,
  `clientname` varchar(255) NOT NULL,
  `clientpass` varchar(255) NOT NULL,
  `clientmail` varchar(255) NOT NULL,
  `clientvname` varchar(255) NOT NULL,
  `clientnname` varchar(255) NOT NULL,
  `clientadress` varchar(255) NOT NULL,
  `clientplz` int(5) NOT NULL,
  `clientort` varchar(255) NOT NULL,
  PRIMARY KEY (`cid`)
)

`dls_kategorien` (
  `kid` int(11) NOT NULL AUTO_INCREMENT,
  `kname` varchar(255) NOT NULL,
  PRIMARY KEY (`wid`)
)

`dls_reload` (
  `ip` varchar(255) NOT NULL,
  `bid` int(11) NOT NULL,
  `bis` int(11) NOT NULL
)

`dls_sizes` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `size` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`sid`)
)

`dls_sizes_kategorien` (
  `sid` int(11) NOT NULL,
  `wid` int(11) NOT NULL
)

Vorgehensweise

1. Schritt Beim erstellen eines Werbebanners bekommt der Werbebanner via AUTO_INCREMENT `bid` und für uns relevant den `status` = 0 und `size` (die passende `sid` (sizeid) im beispiel jetzt `1` und `prio` = 3) und die Menge die ausgeliefert werden darf `bmenge_noch`Dies alles in `dls_banner`

2. Schritt Ich schalte den Werbebanner frei und ändere `status` = 0 auf `status` = 1 (`status`= 2 währe für ein "standby" Modus gedacht) auch in `dls_banner`

3. Schritt Jetzt kommt die Auslieferung.
Bevor wir aber Ausliefern löschen wir aus dls_reload alle Einträge welche bis < time() sind.

Übergeben bekomme ich die Größe die er haben soll und die Kategorie ($size, $kategorie) beides Zahlen als (sid, kid)
Die Auslieferung sollte unter folgenden Bedingungen sein

Werbebanner ist freigeschaltet (status = 1)
Werbebanner soll noch "guthaben" haben
Werbebanner darf in dieser Kategorie angezeigt werden
Werbebanner hat die richtige größe
Werbebanner ist für die IP nicht im Reload

4. Schritt in die dls_reload wird ein Eintrag gemacht mit Bannerid (`bid`) der ClientIP (127.0.0.1) und einen Timestamp bis wann der Banner im Reload ist `bis`


Hoffe ich habe jetzt nichts wichtiges vergessen..
 
Zurück