In einer Spalte nur eine bestimmte Sache ausgeben

exeto

Benutzer
Beiträge
9
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?
 
Werbung:

akretschmer

Datenbank-Guru
Beiträge
9.028
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?

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)
 

exeto

Benutzer
Beiträge
9
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?
 

akretschmer

Datenbank-Guru
Beiträge
9.028
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?

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)
 

ukulele

Datenbank-Guru
Beiträge
4.394
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'
 

akretschmer

Datenbank-Guru
Beiträge
9.028
Auf eine Zeilensortierung im Subselect würde ich verzichten wenn es geht.

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)
 

exeto

Benutzer
Beiträge
9
Ich kann jetzt nicht mehr so ganz folgen. EXPLAIN funktioniert nicht, er kennt die Prozedur nicht.
 

akretschmer

Datenbank-Guru
Beiträge
9.028
Ich kann jetzt nicht mehr so ganz folgen. EXPLAIN funktioniert nicht, er kennt die Prozedur nicht.

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.
 

exeto

Benutzer
Beiträge
9
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

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.
 

ukulele

Datenbank-Guru
Beiträge
4.394
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?
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.

Aufjedenfall klappt es bei mir noch nicht richtig.
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 :)
 

exeto

Benutzer
Beiträge
9
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.

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.
 
Werbung:

ukulele

Datenbank-Guru
Beiträge
4.394
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?
 
Oben