Archiv verlassen und diese Seite im Standarddesign anzeigen : JOINs (ich bin zu blöd)
Hallo,
erstmal vielen Dank an alle, die hier im Forum so fleißig schreiben! Ihr habt mir schon oft geholfen :)
Das mit den JOINs habe ich (glaube ich) im Prinzip verstanden. Aber irgendwie bekomme ich das in meinem Fall nicht hin :(
Hier mal das Script, von dem ich bis vor kurzem noch dachte, dass es das ist, was ich brauche:
$result = mysql_query("SELECT artist FROM artists
WHERE letter = '{$HTTP_GET_VARS['letter']}'
ORDER BY artist LIMIT {$HTTP_GET_VARS['astart']}, 30");
while ($row = mysql_fetch_object($result))
{
$artist = $row->artist;
$result2 = mysql_query("SELECT artist FROM Artikel
WHERE artist = '$artist' AND bestand > 0
OR artist2 = '$artist' AND bestand > 0
OR artist3 = '$artist' AND bestand > 0
OR artists like '% $artist %' AND bestand > 0");
$num2 = mysql_numrows($result2);
if ($num2 > 0)
{
echo "<a href='artist-show.php?artist=$artist>$artist</a> ($num2 items)<br>";
}
}
Habe der Übersichtlichkeit halber gekürzt. Das bisherige Ergebnis ist hier anzuschauen: http://www.reduktivemusiken.de/shop2/artist-index.php
Was ich nicht bedacht habe ist, dass keine 30 "Artists" mehr gelistet werden, wenn $num2 = 0 ist. Was nicht nur unschön ist, sondern in Einzelfällen dazu führen kann, dass die letzten gar nicht mehr gelistet werden...
Ich habe es bisher leider nicht hinbekommen die SQL-Abfrage innerhalb der Schleife in die ursprüngliche einzubauen. Liegt es vielleicht daran, dass es gar kein JOIN ist den ich hier brauche?
Wäre schön wenn mir jemand das an meinem Beispiel erklären kann.
Dank in voraus
Dieter (PHP/SQL-Anfänger)
mach mal so:
select a.artist from artists a inner join artikel b on a.artist=b.artist
where a.letters = ... and b.bestand ... b.artist2 ...
order by ...
limit ....
setze Klammer bei where-Bedingung richtig ein, dann bekommst du auch richtiges Ergebnis; überall, wo $artist steht, ersetzt du mit a.artist, bei dem letzten wende den + operator an, um das Argument für like zusammenzubauen
MelloPie 08-01-2007, 21:09 wenn Du das mit den Joins kapiert hast, warum machste dann kein join?
hui, das ging ja schnell :)
muss mich jetzt um die kinder kümmern. ich probier es morgen. sieht schon mal vielversprechend aus.
(hab den INNER JOIN also vom Prinzip her nicht verstanden ;) )
@ MelloPie:
berechtigte frage.
antwort:
weil meine versuche alle gescheitert sind und ich zum weiterarbeiten ein erstmal funktionierendes script brauchte. mein fehler: ich habe die fehlversuche frustriert gelöscht und konnte sie deshalb nicht posten...
Da bin ich wieder.
So sieht die Abfrage jetzt aus:
$result = mysql_query("SELECT a.artist FROM artists a
INNER JOIN Artikel b
ON a.letter = '{$HTTP_GET_VARS['letter']}'
WHERE (b.artist=a.artist) AND (b.bestand > 0)
OR (b.artist2=a.artist) AND (b.bestand > 0)
OR (b.artist3=a.artist) AND (b.bestand > 0)
OR (b.artists LIKE '% '+a.artist+' %') AND (b.bestand > 0)
GROUP BY a.artist
ORDER BY a.artist
LIMIT {$HTTP_GET_VARS['astart']}, $ds_anzahl")
while ($row = mysql_fetch_object($result))
{...
Habe, denke ich, alle Varianten an Klammersetzung bei der WHERE-Bedingung ausprobiert. Auch alle Klammern noch einmal zusammen zu klammern.
Die Abfrage von b.bestand macht er nicht. Es werden immer auch alle Musiker (artist) gelistet, bei denen bestand = 0 ist.
Gleiches passiert, wenn ich "b.bestand > 0" bei der ON-Bedingung mit rein schreibe (was aufgrund der Datenmenge die Performance stark beeinflusst).
Eine Idee was ich falsch mache?
was soll der Unfug: ON a.letter = '{$HTTP_GET_VARS['letter']}' ?
weisst du überhaupt was in ON anzugeben ist? wenn nicht :rtfm:
Zugegeben, da habe ich rumprobiert. aber Du wirst lachen, da komme ich (von der b.bestand-Abfrage mal abgesehen) zum gewünschten Ergebnis.
mit
ON (b.artist = a.artist OR b.artist2 = a.artist OR b.artist3 = a.artist)
WHERE ((a.letter = '{$HTTP_GET_VARS['letter']}')
AND ...
ignoriert er die Bedingung komplett
mit
ON a.artist = b.artist
wie Du es beschrieben hast, genauso. mit dem Unterschied, dass viele Datensätze nicht mehr berücksichtigt werden.
zum besseren Verständnis hier mal eine genauere beschreibung von dem, was ich will:
der link: http://reduktivemusiken.de/shop2/artist-index.php?letter=A
(letter "A" ist ausgewählt)
besagte Tabellen in der Datenbank
artists
| id | artist | letter |
Artikel
| id | artist | artist2 | artist3 | artists | bestand |
(ohne die Spalten, die hier nicht abgefragt werden)
artists/letter wird vorher für das Menü abgefragt (was auch hervoragend funktioniert).
Es sollen aber nicht alle Daten aus artists/artist mit gewähltem letter angezeigt werden, sondern nur diejenigen, die in Artikel in artist, artist2 oder artist3 stehen oder u.a. in artists.
Und hier soll noch einmal selektiert werden: nur die Datensätze mit bestand>0 sollen berücksichtigt werden.
beispiel:
artists
| id | 1
| artist | Audible Pain
| letter | A
----
| id | 2
| artist | Mundkrach
| letter | M
Artikel
| id | 1
| artist | Audible Pain
| artist2 |
| artist3 |
| artists |
| bestand | 1
----
| id | 2
| artist | Mundkrach
| artist2 | Audible Pain
| artist3 |
| artists |
| bestand | 0
------
"Audible Pain" soll gelistet werden, denn die Soloveröffentlichung hat bestand>0. Ausgabe bei Auswahl letter=A:
Audible Pain (1 items)
"Mundkrach" soll bei Auswahl letter=M nicht gelistet werden, da bestand=0 ist.
--
Das funktionierte mit meinem ursprünglichen Skript bereits. Aber die Ausgabe auf mehreren Seiten (LIMIT) hat da natürlich nicht richtig funktioniert...
Das Script, wie es bei dem Link aktuell ist:
$result = mysql_query("SELECT a.artist FROM ".$PREFIX."_artists a
INNER JOIN ".$PREFIX."_Artikel b
ON (b.artist = a.artist OR b.artist2 = a.artist OR b.artist3 = a.artist)
WHERE ((a.letter = '{$HTTP_GET_VARS['letter']}')
AND (b.artist=a.artist AND b.bestand > 0)
OR (b.artist2=a.artist AND b.bestand > 0)
OR (b.artist3=a.artist AND b.bestand > 0)
OR (b.artists LIKE '% '+a.artist+' %' AND b.bestand > 0))
GROUP BY a.artist
ORDER BY a.artist
LIMIT {$HTTP_GET_VARS['astart']}, $ds_anzahl");
while ($row = mysql_fetch_object($result))
{...
Das Ergebnis ist, wie man sieht, absolut nicht das gewünschte.
Hoffe ich habe es verständlich ausgedrückt.
Original geschrieben von dieter2
ON (b.artist = a.artist OR b.artist2 = a.artist OR b.artist3 = a.artist)
WHERE ((a.letter = '{$HTTP_GET_VARS['letter']}')
AND (b.artist=a.artist AND b.bestand > 0)
OR (b.artist2=a.artist AND b.bestand > 0)
OR (b.artist3=a.artist AND b.bestand > 0)
OR (b.artists LIKE '% '+a.artist+' %' AND b.bestand > 0))
Na ja, gleichlautende Bedingungen im ON und im WHERE unterzubringen, kann doch wohl schon mal nicht sinn der Sache sein.
Und warum du die Bestand-Bedingung auch jedes Mal abfragen willst, ist mir auch unverständlich.
Ausserdem wäre die vielleicht besser bei HAVING untergebracht, als bei WHERE.
Hast du dich mit dem Sticky Thread hier im Forum schon beschäftigt? Insb. auch die Links zu den Artikeln bei SELFHTML beachtet?
$result = mysql_query("SELECT a.artist FROM artists a
INNER JOIN Artikel b
ON (b.artist = a.artist
OR b.artist2 = a.artist
OR b.artist3 = a.artist
OR b.artists LIKE '% '+a.artist+' %')
WHERE a.letter = '{$HTTP_GET_VARS['letter']}'
GROUP BY a.artist
HAVING b.bestand > 0
ORDER BY a.artist
LIMIT {$HTTP_GET_VARS['astart']}, $ds_anzahl")
ok, danke!
jetzt sieht das ergebnis schon wieder besser aus.
aber lasse ich b.bestand>0 in der WHERE-Bedingung stehen, wird sie weiterhin ignoriert :(
steht sie so wie oben in der HAVING kommt folgende Fehlermeldung:
Unknown column 'b.bestand' in 'having clause'
:confused:
die spalte existiert aber garantiert und wird auch so geschrieben. wahrscheinlich wird sie bei WHERE dann auch nicht gefunden.
eine idee warum? ein syntax-fehler?
p.s.: um die links kümmer ich mich später. insbesondere um die artist- übergabe (sonder- und leerzeichen)
jetzt bin ich anscheinend komplett an meine grenzen gestoßen...
die abfrage schaut jetzt so aus:
$result = mysql_query("SELECT a.artist, b.bestand FROM artists a
INNER JOIN Artikel b
ON (b.artist1 = a.artist
OR b.artist2 = a.artist
OR b.artist3 = a.artist
OR b.artists LIKE '% '+a.artist+' %')
WHERE a.letter = '{$HTTP_GET_VARS['letter']}'
GROUP BY a.artist
HAVING b.bestand > 0
ORDER BY a.artist
LIMIT {$HTTP_GET_VARS['astart']}, $ds_anzahl")
und funktioniert auch fast gut.
aber eben nur fast: es werden nicht alle artists gelistet und ich habe auch herausgefunden warum.
habe ich bei einem artist mehrere datensätze in tabelle Artikel und bei einem davon ist bestand=0 kann es passieren, dass der satz nicht ausgegeben wird.
das kann ich umgehen, indem ich die GROUP BY klausel raus nehme. aber dann werden alle artists 4-6x gelistet unabhängig davon, wie viele datensätze vom jeweiligen vorhanden sind :confused:
da stellt sich mir die frage, ob ich mit INNER JOIN überhaupt auf dem richtigen weg bin? oder habe ich etwas noch immer nicht richtig verstanden?
versuch schon seit knapp 3,5 stunden das prob zu knacken...
HIIILFEEE!!!
habe die ganze abfrage noch einmal neu gebastelt:
$result = mysql_query("SELECT a.artist, COUNT(b.bestand) AS items
FROM artists a, Artikel b
WHERE a.letter = '{$HTTP_GET_VARS['letter']}'
AND (b.artist1 = a.artist
OR b.artist2 = a.artist
OR b.artist3 = a.artist
OR b.artists LIKE '% '+a.artist+' %')
AND b.bestand>0
GROUP BY a.artist
HAVING items>0
ORDER BY a.artist
LIMIT {$HTTP_GET_VARS['astart']}, $ds_anzahl")
diesmal ohne JOIN und komme leider zum selben ergebnis :(
http://reduktivemusiken.de/shop2/artist-index.php?letter=A
hatte eigentlich erwartet (erhofft), dass der COUNT die WHERE-Bedingung berücksichtigt.
die zahl am ende jeder ausgabe ist das COUNT-ergebnis. wollte eigentlich die zahl davor als ergebnis haben, die aus der abfrage in der folgenden schleife kommt (siehe 1. beitrag).
wenn ich es so hinbekomme hätte es den vorteil, dass ich die 2. abfrage spare und sich die performance erhöht.
sieht jemand einen denkfehler? oder habe ich schon wieder etwas nicht verstanden :(
ministry 12-01-2007, 14:15 Dass das so kompliziert ist, liegt an deinem komischen Datenbankdesign...
logischer wäre folgender Aufbau:
Tabelle artists
-- id
-- name
Tabelle artikel
-- id
-- bestand
(-- ev. name...)
Tabelle lookup
-- artikel_id
-- artist_id
Das mit der extra Letter-Spalte ist auch unglücklich. Besser wäre es mit Stringfunktionen, z.b. LEFT().
Dann könntest du einfach so tun:
SELECT artists.name FROM artists INNER JOIN lookup ON artists.id = artist_id INNER JOIN artikel ON artikel_id = artikel.id WHERE LEFT(artists.name,1) = '$letter' AND bestand > 0
Oder ähnlich. Das wäre viel schlüssiger.
spalte letter wird bleiben. denn so kann ich rubriken einbauen, die zeichenunabhängig sind. eine band nennt sich z.b. [-hyph-] und ich möchte kein "[" im menü haben. der soll entweder bei "H" oder bei "OTHER" stehen. und magazine entziehen sich auch der reinen buchstabenzuweisung.
tabelle lookup klingt recht einfach, auch wenn sie min. 3-4 artikel_id-spalten brauchen wird damit die aufteilung auf der artist-show.php funktioniert. ist aber ein kleineres prob. was mir weniger daran gefällt ist, dass ich dann keine updates mehr per csv-datei machen kann. ist aber auch nicht das schlimmste.
das schlimmste wird es sein die bestehenden fast 1000 datensätze anzupassen...
wenn du oder wer anders noch eine idee hat, wie ich die jetzige abfrage hinbekomme (mit oder ohne JOIN), würde das sääähr helfen.
ansonsten habe ich wohl noch sehr viel arbeit vor mir... :{
|
-
- |