Scooter: SQL-Abfrage über 2 Tabellen

Hi,

ich habe zwei Tabellen zu einem Online-Shop:

Kategorien und Produkte.

Jedes Produkt bekommt über einen Fremdschlüssel eine Kategorie zugeordnet.
Jedes Produkt hat eine Anzahl.

Nun möchte ich alle Kategorien anzeigen lassen, zu der es mindestens ein Produkt gibt, dessen Anzahl größer als Null ist. (es können Produkte gespeichert sein, die ausverkauft sind, also Anzahl = 0, dessen Kategorien sollen nicht angezeigt werden)

Wie mach ich das?

Habe folgendes versucht:

SELECT * FROM shop_categories, shop_products
WHERE shop_categories.categories_id = shop_products.categories_id
AND shop_products.anzahl > 0

Problem ist: wenn es mehrere Produkte gibt, die zur selben Kategorie gehören, dann wird diese Kategorie auch mehrmals aufgelistet. Natürlich soll sie nur genau einmal aufgelistet werden.

LIMIT 1 hilft da ja leider auch nicht, da dann immer nur eine Kategorie gelistet wird.

Habt ihr ne Idee??

Gruß
Scooter

  1. Moin,

    Problem ist: wenn es mehrere Produkte gibt, die zur selben Kategorie gehören, dann wird diese Kategorie auch mehrmals aufgelistet. Natürlich soll sie nur genau einmal aufgelistet werden.

    Du suchst DISTINCT.

    --
    Henryk Plötz
    Grüße aus Berlin
    ~~~~~~~~ Un-CDs, nein danke! http://www.heise.de/ct/cd-register/ ~~~~~~~~
    ~~ Help Microsoft fight software piracy: Give Linux to a friend today! ~~
    1. Hi,

      Du suchst DISTINCT.

      Hey, danke. Hast mir glaub ich schon geholfen. Allerdings weiß ich noch nicht so genau wie DISTINCT arbeitet:

      Ich habe es nach dem SELECT geschrieben. Woanders darf es wohl nicht hin.

      --> SELECT DISTINCT ...

      wenn ich dann ein * nehme, klappts nicht. wenn ich nur die Spalten nehme, die ich brauche klappts!

      Genauer gesagt habe ich heraus gefunden, wenn ich die Produkt ID noch mit hinzunehme, klappts nicht.

      Wie arbeitet DISTINCT nun?? Ich finde darüber in der MySQL-Sprachreferenz nicht. Muss jeder Wert der ausgeählten Spalten unterschiedlich sein?? Oder wählt es bei Spalten in denen sich werte wiederholen nur einen aus? Welchen dann?
      Wieso klappts nicht wenn ich alle Spalten auswähle??

      Gruß
      Scooter

      1. Moin,

        Wie arbeitet DISTINCT nun?? Ich finde darüber in der MySQL-Sprachreferenz nicht.

        Naja, es hat nicht grade epische Breite, wird aber doch erwähnt:
        | The options DISTINCT, DISTINCTROW and ALL specify whether duplicate
        | rows should be returned. The default is (ALL), all matching rows are
        | returned. DISTINCT and DISTINCTROW are synonyms and specify that
        | duplicate rows in the result set should be removed.
         -- MySQL-Referenzmanual, Abschnitt 6.4.1

        Muss jeder Wert der ausgeählten Spalten unterschiedlich sein??

        Jeder der Werte die du dir zurückgeben lässt darf nur einmal vorkommen. Hast du also eine Tabelle
        Typ | Name
        ----+------------
        Obst| Birne
        Obst| Apfel
        Pilz| Fliegenpils

        und machst ein SELECT Typ FROM ... kriegst du Obst, Obst, Pilz. Machst du hingegegen SELECT DISTINCT Typ FROM ... kriegst du Obst, Pilz. SELECT DISTINCT * FROM ... würde dir hier nichts bringen, da ja alle Zeilen die er dir zurückgibt unterschiedlich sind.

        Oder wählt es bei Spalten in denen sich werte wiederholen nur einen aus? Welchen dann?

        Den ersten auf den es trifft. Wobei hier die Reihenfolge vermutlich nicht definiert ist. Für deine Betrachtungen solltest du also von "irgendeinen zufälligen" ausgehen.

        Wieso klappts nicht wenn ich alle Spalten auswähle??

        Ich nehme an dass du da noch IDs oder ähnliches hast die ohnehin immer unterschiedlich sind. So kann er die Spalten nicht als gleich erkennen.

        --
        Henryk Plötz
        Grüße aus Berlin
        ~~~~~~~~ Un-CDs, nein danke! http://www.heise.de/ct/cd-register/ ~~~~~~~~
        ~~ Help Microsoft fight software piracy: Give Linux to a friend today! ~~
        1. Servus,

          Du musst das ganze auf zwei Abfragen ausweiten.
          Die erste liefert Dir eine Liste mit den Kathegorieren und die zweite arbeitet die Liste in aller ruhe ab und liefert zu jeder Kathegorie einen artikel.

          Möglihckeiten gibt es dazu gerade ma genug.

          Die erste wäre über einen join.
          Das klappt jedoch nur in einer etwas höherwertigen Sprache wie PL/SQL T-SQL etc. leider nicht mit SQL selbst.

          Sicher doch joinen kann man auch mit SQL  aber nicht in dem Umfang wie wir es hier benötigen.

          2. Möglihckeit die bessere öffnen eine Abfrge mit der Du eine Liste der Kathegorien holst z.B:

          Sinngemäss!

          result1 = sqlqery ("select katid from kathegorytable order by katname);

          Jetzt musst Du erstes Script in eine while Schleife auswerten

          while(result1)

          result2 = sqlqery ("select prodid, prodname from prodtable where prodkatid = "+ result1 + " order ba prodname;

          Ich hoffe Du kannst mit der eher Theoretischen und Syntaktisch völlig verhunzten Info was anfangen.

          Gruss Matze

          1. Hi,

            while(result1)

            result2 = sqlqery ("select prodid, prodname from prodtable where prodkatid = "+ result1 + " order ba prodname;

            hm, dann hätte ich damit alle Produkte die einer kategorie zugeordnet sind.
            weiß nicht ob mir das so hilft.

            Das mit dem DISTINCT war schon ganz gut. Muss nur sehen, ob es auch wirklich für alle Fälle zutrifft.

            Scooter

            1. Dann must Du eben das zweite SQL etwas anpassen.
              Das mit dem Distinct kannst Du gerne machen aber ohene obige Lösung kommst du nicht richtig dran, so wie Du es Beschrieben hast.

              Gruss Matze

              1. Moin,

                Dann must Du eben das zweite SQL etwas anpassen.
                Das mit dem Distinct kannst Du gerne machen aber ohene obige Lösung kommst du nicht richtig dran, so wie Du es Beschrieben hast.

                Woran denn nun wieder? Der Ursprungsposter wollte eine Liste aller Kategorien in denen es ein Produkt gibt von dem noch mindestens ein Stück im Lager ist. Dazu holen wir uns eine Liste aller Produkte mit Anzahl > 0, joinen das mit der Kategorieliste und haben somit alle Produkte mit mindestens einem Stück im Lager und deren Kategorien. Die Produkte brauchen wir gar nicht sondern SELECTen nur die Kategorien. Das gibt schonmal die Liste wie wir sie haben wollen, bloß das eben noch Kategorien mehrfach auftauchen können. Genau daran dreht DISTINCT (bzw. GROUP BY Kategorie, aber eben unter Umständen weniger effizient).

                Mir ist unklar wo du da die Notwendigkeit für zwei Abfragen sehen willst. (Zumal die Aufgabenstellung die du offenbar zu lösen glaubtest auch genau das Einsatzgebiet von JOINs ist. Möchtest du dich vielleicht noch ein bisschen mit SQL befassen bevor du wieder was dazu sagst?)

                --
                Henryk Plötz
                Grüße aus Berlin
                ~~~~~~~~ Un-CDs, nein danke! http://www.heise.de/ct/cd-register/ ~~~~~~~~
                ~~ Help Microsoft fight software piracy: Give Linux to a friend today! ~~
                1. Servus,

                  lieber henryk

                  Mir ist unklar wo du da die Notwendigkeit für zwei Abfragen sehen >>willst. (Zumal die Aufgabenstellung die du offenbar zu lösen >>glaubtest auch genau das Einsatzgebiet von JOINs ist. Möchtest du >>dich vielleicht noch ein bisschen mit SQL befassen bevor du wieder >>was dazu sagst?)

                  tut mir sehr leid hab die Frage etwas falsch verstanden aber Deine "Arroganz" ist grad mal an der falchen Ecke gelandet.

                  Gruss Matze

                  1. Moin,

                    tut mir sehr leid hab die Frage etwas falsch verstanden aber Deine "Arroganz" ist grad mal an der falchen Ecke gelandet.

                    Dass du die Frage falsch verstanden hast war offensichtlich. Aber das mit dem nochmal anschauen hatte ich ernst gemeint. Vielleicht auch bloß weil ich nicht verstehe inwiefern dein

                    | result1 = sqlqery ("select katid from kathegorytable order by katname);
                    | while(result1)
                    |  result2 = sqlqery ("select prodid, prodname from prodtable where prodkatid = "+ result1 + " order ba prodname;

                    etwas anderes liefert, oder in irgendeiner Form besser ist, als
                    SELECT katid, prodid, prodname FROM kathegorytable, prodtable WHERE prodkatid = katid ORDER BY katname, prodname
                    vor allem da du im selben Post vorher behauptest hast "joinen kann man auch mit SQL  aber nicht in dem Umfang wie wir es hier benötigen".

                    --
                    Henryk Plötz
                    Grüße aus Berlin
                    ~~~~~~~~ Un-CDs, nein danke! http://www.heise.de/ct/cd-register/ ~~~~~~~~
                    ~~ Help Microsoft fight software piracy: Give Linux to a friend today! ~~
                    1. Servus,

                      wie schon gesagt ich habe die Fragestellung falsch verstanden.
                      Somit ist auch der "join" den ich für,angemessen gehalten hätte über SQL nicht mehr möglich.

                      Gruss matze

                      PS Ich  weiss eure grösste Freude ist es doch teilweise in dem Forum jemanden der falsch liegt als Narren hinzustellen.

    2. Hi Henryk,

      Problem ist: wenn es mehrere Produkte gibt, die zur selben Kategorie gehören, dann wird diese Kategorie auch mehrmals aufgelistet. Natürlich soll sie nur genau einmal aufgelistet werden.
      Du suchst DISTINCT.

      was hältst Du von "GROUP BY"?

      Viele Grüße
            Michael

      --
      T'Pol: I apologize if I acted inappropriately.
      V'Lar: Not at all. In fact, your bluntness made me reconsider some of my positions. Much as it has now.
      (sh:| fo:} ch:] rl:( br:^ n4:( ie:% mo:) va:| de:/ zu:| fl:( ss:) ls:~ js:|)
       => http://www.peter.in-berlin.de/projekte/selfcode/?code=sh%3A|+fo%3A}+ch%3A]+rl%3A(+br%3A^+n4%3A(+ie%3A%25+mo%3A)+va%3A|+de%3A%2F+zu%3A|+fl%3A(+ss%3A)+ls%3A~+js%3A|
      Auch diese Signatur wird an korrekt konfigurierte Browser gzip-komprimiert übertragen.
      1. Moin,

        was hältst Du von "GROUP BY"?

        Weniger. MySQL wandelt DISTINCT zwar intern in GROUP BY um, kann bei DISTINCT aber unter Umständen früher aufhören die Tabellen zu durchsuchen. Siehe MySQL-Referenz, Abschnitt 5.2.5.

        --
        Henryk Plötz
        Grüße aus Berlin
        ~~~~~~~~ Un-CDs, nein danke! http://www.heise.de/ct/cd-register/ ~~~~~~~~
        ~~ Help Microsoft fight software piracy: Give Linux to a friend today! ~~