*jiriki*: SQL: Kann man diese Anfrage simpler gestalten

Hi,

ich hab eine Tabelle 'discs' mit den Attributen 'id' (Primary Key), 'title' und 'ripped' auf einem PostgreSQL-Server. Ripped gibt mir an, ob ich das Album selbst gerippt hab, oder nicht. Das heisst, es kann mehrere Einträge des gleichen Albums geben (mal selbst gerippt, mal nicht, und das ganze öfters).

Jetzt möchte ich jedes Album nur einmal ausgegeben haben, wobei es mir, falls es mehrere Einträge für ein Album gibt, immer das/eines der selbstgerippten Versionen ausspucken soll.

Bisher läuft das bei mir so:

  
CREATE TEMPORARY TABLE result  
SELECT *  
FROM discs  
ORDER BY ripped DESC;  
  
ALTER IGNORE TABLE blubb  
ADD PRIMARY KEY ( name );  
  
SELECT * FROM result;  

Kann man das ganze auch ergonomisch in einem SELECT-Befehl schachteln?

Grüßle, *jiriki*

  1. Hallo,

    warum nicht :
    SELECT * FROM discs ORDER BY ripped DESC limit 1; ??

    1. warum nicht :
      SELECT * FROM discs ORDER BY ripped DESC limit 1; ??

      Ganz so einfach gehts leider nicht. Damit würdest du deine Ausgabemenge auf insg. 1 Datensatz reduzieren. Ich will aber ja zu jedem Album einen Datensatz.

  2. yo,

    welches DBMS benutzt du und welche Version ?

    Ilja

    1. welches DBMS benutzt du und welche Version ?

      Ähm, DBMS ist wie gesagt PostgreSQL (oder verwechsel ich da was?) und Version ist 8.1x.

      1. yo,

        Ähm, DBMS ist wie gesagt PostgreSQL (oder verwechsel ich da was?) und Version ist 8.1x.

        wer lesen kann, ist klar im vorteil, da habe ich wohl was übersehen. ;-)

        was deine abfrage angeht:

        SELECT tab1.id, tab1.title, tab1.ripped
        FROM discs AS tab1
        WHERE tab1.id IN
            (
            SELECT MAX(tab2.id)
            FROM discs AS tab2
            WHERE tab2.ripped = "selbt gerippt"
            GROUP BY tab2.title
            )

        das gibt dir erst einmal einen datensatz pro titel der gerippt wurde. nun musst du das ganze nur noch mit UNION verbinden, bei den titel, die keine gerippte version haben. aber ich weiß nicht, nach welchen kriterien du da eine auswahl treffen willst.

        Ilja

        1. SELECT tab1.id, tab1.title, tab1.ripped
          FROM discs AS tab1
          WHERE tab1.id IN
              (
              SELECT MAX(tab2.id)
              FROM discs AS tab2
              WHERE tab2.ripped = "selbt gerippt"
              GROUP BY tab2.title
              )

          das gibt dir erst einmal einen datensatz pro titel der gerippt wurde. nun musst du das ganze nur noch mit UNION verbinden, bei den titel, die keine gerippte version haben. aber ich weiß nicht, nach welchen kriterien du da eine auswahl treffen willst.

          Mh, dann dürfte ich im zweiten SELECT nur noch die Datensatz-Gruppierungen betrachten, in denen _alle_ Datensätze den Wert "nicht selbst gerippt" in "ripped" haben. Gibt es so eine Klausel im Sinne von

            
          GROUP BY x  
          HAVING ALL y = "not self ripped"  
          
          

          ?

          Greets, *jiriki*

          1. yo,

            Mh, dann dürfte ich im zweiten SELECT nur noch die Datensatz-Gruppierungen betrachten, in denen _alle_ Datensätze den Wert "nicht selbst gerippt" in "ripped" haben.

            dafür musst du halt zwei bedingungen beachten. zum einen musst du nur die datensätze einschließen, die kein selbst gerippt im jeweiligen Titel haben. und dann musst du dich für einen ripped wert entscheiden. ich weiß aber nicht welchen du willst und so nehmen ich einfach einen mit MAX().

            SELECT tab1.id, tab1.title, tab1.ripped
            FROM discs AS tab1
            WHERE tab1.id IN
               (
               SELECT MAX(tab2.id)
               FROM discs AS tab2
               GROUP BY tab2.titel
               )
            AND 0 =
               (
               SELECT COUNT(*)
               FROM discs AS tab3
               WHERE tab3.ripped = "self ripped"
               AND tab3.titel = tab1.titel
               )

            eine andere möglichkeit wären Operatoren der Mengenlehre wie INTERCEPT oder andere. aber ich weiß nicht, ob dein dbms so etwas unterstützt.

            Ilja

            1. eine andere möglichkeit wären Operatoren der Mengenlehre wie INTERCEPT oder andere. aber ich weiß nicht, ob dein dbms so etwas unterstützt.

              Mal angenommen, es unterstützt diese Operatoren. Gäbe es dann eine etwas schlankere Anfrage als die bisher erarbeitete? Mir gefällt die Lösung mit der Temporary Table bisher besser, weil sie codemäßig kürzer ist (auch wenn ich nicht weiss, wie sich das speicherplatzmäßig auswirkt (TemporaryTable <-> Nur Select-Anfrage)).

              Also an einer Mengenoperatorenlösung wäre ich durchaus interessiert. Danke schonmal für bisherige Hilfe, *jiriki*

              1. yo,

                Also an einer Mengenoperatorenlösung wäre ich durchaus interessiert. Danke schonmal für bisherige Hilfe, *jiriki*

                ok, ich habe mir noch keine kokreten gedanken gemacht, sag doch mal, welche Operatorem bezüglich von mengen kann den dein dbms ?

                Ilja

                1. ok, ich habe mir noch keine kokreten gedanken gemacht, sag doch mal, welche Operatorem bezüglich von mengen kann den dein dbms ?

                  Soweit ich weiss, unterstützt PostgreSQL den größten Teil der SQL-Syntax. Die Mengenoperatoren "UNION", "INTERSECT" und "EXCEPT" ("MINUS") auf jeden Fall. Gibts weitere?

                  Unter http://www.postgres.de/features.html steht da auch kurz und übersichtlich, was unterstützt wird.

                  Greets, *jiriki*

                  1. yo,

                    noch mal eine lösungsvorschlag ohne mengenoperatoren, der aber nur im speziellen fall funktioniert, nämlich dann, wenn die spalte ripped als aggregatfunktion MIN(), bzw. MAX() den wert "selbst geribbt auswirft. dann könnte man nämlich nur eine unterabfrage machen und hätte alle auf einmal.

                    den link schaue ich mir morgen an....

                    Ilja