Information ausblenden
Willkommen im Forum für alle Datenbanken! Registriere Dich kostenlos und diskutiere über DBs wie Mysql, MariaDB, Oracle, Sql-Server, Postgres, Access uvm

In einer Spalte nur eine bestimmte Sache ausgeben

Dieses Thema im Forum "Microsoft SQL Server" wurde erstellt von exeto, 18 Oktober 2013.

  1. exeto

    exeto Benutzer

    Ich habe eine Tabelle mit 3 Spalten.
    Automarke - Modell - Farbe

    Ich will jetzt alle Automarken und alle Modelle ausgegeben haben egal welche Farbe.
    In der Farbspalte soll nix drin stehen außer bei denen mit der Farbe blau.

    Da soll dann true oder blau drin stehen, die restlichen Felder sollen leer bleiben. Trotzdem werden aber halt Automarke und Modell angezeigt nur das Farbfeld bleibt leer wenn es nicht blau ist.

    Ist so etwas möglich?
     
  2. akretschmer

    akretschmer Datenbank-Guru

    Natürlich nicht, wo kämn wir da hin?

    Code:
    test=*# select * from exeto ;
    marke | modell | farbe
    -------+--------+-------
    audi  | a4    | blau
    audi  | a3    | rot
    opel  | astra  | gelb
    vw    | golf  | blau
    (4 rows)
    
    Time: 0,171 ms
    test=*# select marke, modell, case when farbe = 'blau' then farbe else null end as farbe from exeto ;
    marke | modell | farbe
    -------+--------+-------
    audi  | a4    | blau
    audi  | a3    |
    opel  | astra  |
    vw    | golf  | blau
    (4 rows)
    
     
  3. exeto

    exeto Benutzer

    Danke, klappt, "fast" perfekt.
    Einmal hat der Spaltenname den Namen "Kein Spaltenname".
    Wenn jetzt z.B. der Audi A3, 10 verschiedene Farben hat, aber nicht die Farbe blau, wird er trotzdem 10 mal angezeigt. Hier habe ich es schon hinbekommen, dass nur noch einer angezeigt wird mit DISTINCT.

    Wenn ich jetzt aber nen Audi a4 in blau und einen in rot in der Tabelle habe. Dann zeigt er mir es ja so an:

    Code:
    audi  | a4    | blau
    audi | a4    |
    audi  | a3    |
    opel  | astra  |
    vw    | golf  | blau
    
    Ist es da möglich, wenn es einen blauen gibt. Die anderen nicht anzuzeigen? Also hier den roten a4?
     
  4. akretschmer

    akretschmer Datenbank-Guru

    Vielleicht so:

    Code:
    test=*# select * from exeto ;
    marke | modell | farbe
    -------+--------+-------
    audi  | a4    | blau
    audi  | a3    | rot
    opel  | astra  | gelb
    vw    | golf  | blau
    audi  | a4    | rot
    (5 rows)
    
    Time: 0,181 ms
    test=*# select marke, modell, case when farbe = 'blau' then farbe else null end as farbe, row_number() over (partition by marke, modell order by (case when farbe = 'blau' then 0 else 1 end)) from exeto ;
    marke | modell | farbe | row_number
    -------+--------+-------+------------
    audi  | a3    |      |          1
    audi  | a4    | blau  |          1
    audi  | a4    |      |          2
    opel  | astra  |      |          1
    vw    | golf  | blau  |          1
    (5 rows)
    
    Das als Subselect mit where row_number = 1:

    Code:
    test=*# select * from (select marke, modell, case when farbe = 'blau' then farbe else null end as farbe, row_number() over(partition by marke, modell order by (case when farbe = 'blau' then 0 else 1 end)) from exeto ) foo where row_number = 1;
    marke | modell | farbe | row_number
    -------+--------+-------+------------
    audi  | a3    |      |          1
    audi  | a4    | blau  |          1
    opel  | astra  |      |          1
    vw    | golf  | blau  |          1
    (4 rows)
    
     
  5. ukulele

    ukulele Datenbank-Guru

    Auf eine Zeilensortierung im Subselect würde ich verzichten wenn es geht. Aber hier mal noch 2 Alternativen:
    Code:
    SELECT    DISTINCT
            marke,
            modell,
            (    SELECT    'x'
                FROM    exeto t2
                WHERE    t2.farbe = 'blau'
                AND        t2.marke = exeto.marke
                AND        t2.modell = exeto.modell ) AS farbe
    FROM    exeto
    Code:
    SELECT    t1.marke,
            t1.modell,
            t2.farbe
    FROM    (    SELECT    DISTINCT
                        marke,
                        modell
                FROM    exeto ) t1
    LEFT JOIN (    SELECT    DISTINCT
                        marke,
                        modell,
                        farbe
                FROM    exeto ) t2
    ON        t1.marke = t2.marke
    AND        t1.modell = t2.modell
    WHERE    t2.farbe = 'blau'
     
  6. akretschmer

    akretschmer Datenbank-Guru

    Hab mal EXPLAIN geschaut:

    Code:
    test=*# explain SELECT    DISTINCT
            marke,
            modell,
            (    SELECT    'x'::text FROM    exeto t2
                WHERE    t2.farbe = 'blau'
                AND        t2.marke = exeto.marke
                AND        t2.modell = exeto.modell ) AS farbe
    FROM    exeto;
                                                  QUERY PLAN
    --------------------------------------------------------------------------------------------------------
    HashAggregate  (cost=6.52..10.91 rows=4 width=8)
      ->  Seq Scan on exeto  (cost=0.00..6.49 rows=5 width=8)
            SubPlan 1
              ->  Seq Scan on exeto t2  (cost=0.00..1.09 rows=1 width=0)
                    Filter: ((farbe = 'blau'::text) AND (marke = exeto.marke) AND (modell = exeto.modell))
    (5 rows)
    
    Code:
    test=*# explain SELECT    t1.marke,
            t1.modell,               
            t2.farbe                 
    FROM    (    SELECT    DISTINCT   
                        marke,       
                        modell       
                FROM    exeto ) t1   
    LEFT JOIN (    SELECT    DISTINCT 
                        marke,       
                        modell,       
                        farbe         
                FROM    exeto ) t2   
    ON        t1.marke = t2.marke     
    AND        t1.modell = t2.modell 
    WHERE    t2.farbe = 'blau';       
                                            QUERY PLAN                                       
    --------------------------------------------------------------------------------------------
    Hash Join  (cost=2.22..2.34 rows=1 width=12)                                             
      Hash Cond: ((exeto.marke = t2.marke) AND (exeto.modell = t2.modell))                   
      ->  HashAggregate  (cost=1.07..1.11 rows=4 width=8)                                     
            ->  Seq Scan on exeto  (cost=0.00..1.05 rows=5 width=8)                           
      ->  Hash  (cost=1.11..1.11 rows=2 width=12)                                             
            ->  Subquery Scan on t2  (cost=1.07..1.11 rows=2 width=12)                       
                  ->  Unique  (cost=1.07..1.09 rows=2 width=12)                               
                        ->  Sort  (cost=1.07..1.08 rows=2 width=12)                           
                              Sort Key: exeto_1.marke, exeto_1.modell                         
                              ->  Seq Scan on exeto exeto_1  (cost=0.00..1.06 rows=2 width=12)
                                    Filter: (farbe = 'blau'::text)                           
    (11 rows)                                                                                 
    
    und meine Version:

    Code:
    test=*# explain select * from (select marke, modell, case when farbe = 'blau' then farbe else null end as farbe, row_number() over (partition by marke, modell order by (case when farbe = 'blau' then 0 else 1 end)) from exeto ) foo where row_number = 1;
                                                      QUERY PLAN                                                 
    ---------------------------------------------------------------------------------------------------------------
    Subquery Scan on foo  (cost=1.11..1.31 rows=1 width=48)                                                     
      Filter: (foo.row_number = 1)                                                                               
      ->  WindowAgg  (cost=1.11..1.25 rows=5 width=12)                                                           
            ->  Sort  (cost=1.11..1.12 rows=5 width=12)                                                         
                  Sort Key: exeto.marke, exeto.modell, (CASE WHEN (exeto.farbe = 'blau'::text) THEN 0 ELSE 1 END)
                  ->  Seq Scan on exeto  (cost=0.00..1.05 rows=5 width=12)                                       
    (6 rows)                                                                                                     
    
     
  7. exeto

    exeto Benutzer

    Ich kann jetzt nicht mehr so ganz folgen. EXPLAIN funktioniert nicht, er kennt die Prozedur nicht.
     
  8. akretschmer

    akretschmer Datenbank-Guru

    EXPLAIN ist ein Befehl, der den Abfrageplan anzeigt. Das ist aber nicht überall und nicht überall gleich implementiert. Oraggle kann es, PostgreSQL wie man sieht. MySQL kann es auch, aber die Ausgabe da ist die Bytes kaum wert.

    M$SQL kann auch sowas, aber das geht da irgendwie anders. Sorry, hätte ich vielleicht erklären sollen.

    Zu den Plänen oben: relevant ist immer das cost = xxx ... yyy in der ersten Zeile des Planes. Das sind imaginäre Zahlen ohne Einheit, aber es ist wie im realen Leben: geringere Kosten ist das, was man eigentlich will. Man kann so unterschiedliche Abfragen, die aber das selbe Resultat liefern, miteinander vergleichen. Ziel ist es, den preiswertesten Plan zu finden. Preiswert im Sinne von: schnell, wenig Last für die DB.
     
  9. exeto

    exeto Benutzer

    Habe das jetzt mal nachgebaut, jetzt krieg ich als Ausgabe noch eine extra Spalte wo nur 'x' drinne ist. Ist das richtig und wofür ist das gut? Aufjedenfall klappt es bei mir noch nicht richtig.
     
  10. ukulele

    ukulele Datenbank-Guru

    Die x Spalte habe ich nur optional mit rein genommen. Wenn du eine Spalte Farbe machst und da steht nur was drin wenn die Farbe Blau ist und sonst nichts dann ist das ja eigentlich nicht korrekt denn es werden ja Farben unterschlagen. Wenn du aber eine Spalte machst die "Blau" heißt (ich hab AS farbe geschreiben aber kann man ja ändern) und halt einen Eintrag mit x markiert ist das vieleicht eher gewünscht.

    In der 2ten Abfrage müssten alle Einträge mit blau ausgegeben werden, die x Spalte kannst du hier einfach raus nehmen. Oder du nimmst die Bedingung t2.farbe='blau' raus dann kommen alle Farben und die jeweils blauen mit einem x.

    @akretschner: Das mit dem Queryplan solltest du wenn dann auch mal für eine Tabelle mit mehr als 5 Einträgen machen. Ich bin jetzt mal davon ausgegangen das ein LEFT JOIN immer schneller ist als ein Subselect. Mag nicht so sein aber bei vielen Einträgen vieleicht doch. Hab selbst jetzt aber nicht so die Zeit, ziehe grade um :)
     
  11. exeto

    exeto Benutzer

    Also wenn ich das t2.farbe='blau' wegnehme dann sagt der mir :
    Code:
    Die Unterabfrage hat mehr als einen Wert zurückgegeben. Das ist nicht zulässig, wenn die Unterabfrage auf =, !=, <, <=, > oder >= folgt oder als Ausdruck verwendet wird.
    Wenn ich aus 'x', Farbe mache, schmeißt der mir überall die Farbe blau aus in der Spalte.
    Wenn ich die 2. Abfrage rauskopiere und einzeln in einer neuen Abfrage teste, dann klappt die Abfrage.
     
  12. ukulele

    ukulele Datenbank-Guru

    Code:
    SELECT    DISTINCT
            marke,
            modell,
            (    SELECT    'blau'
                FROM    exeto t2
                WHERE    t2.farbe = 'blau'
                AND        t2.marke = exeto.marke
                AND        t2.modell = exeto.modell ) AS farbe
    FROM    exeto
    ...geht aber oder?
     
Die Seite wird geladen...

Diese Seite empfehlen

  1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies.
    Information ausblenden