2 Attribute als Matrix anzeigen

Ich habe viele Abfragen über 2 Attribute, die ich als Matrix darstellen will.

Als Liste stelle ich die Werte so dar:

SELECT farbe, mitglied, count (*) 
FROM foo
GROUP BY 1, 2 ORDER BY 1, 2;

Ergebnis:

blau, t, 12
blau, f, 3
gelb, t, 0
gelb, f, 8
 rot, t, 7
 rot, f, 4

Mein Wunsch wäre eine matrixartige Ausgabe:

farbe  ja nein
blau   12 3
gelb    0 8 
rot     7 4

Gehe ich recht in der Annahme, daß es keine kurze, knackige Abkürzung gibt, diese Matrix per SQL erzeugen zu lassen?
Müßte ich mir selbst programmieren…?

Nein.

Müßte ich mir selbst programmieren…?

Nein.

test=*# select * from farbe;
 farbe | mitglied
-------+----------
 blau  | t
 blau  | t
 blau  | f
 rot   | t
 rot   | f
 rot   | f
 gelb  | t
 gelb  | t
 gelb  | t
 gelb  | f
(10 rows)

test=*# select farbe, sum(case when mitglied then 1 else 0 end) as ja, sum(case when mitglied then 0 else 1 end) as nein from farbe group by 1 order by 1;
 farbe | ja | nein
-------+----+------
 blau  |  2 |    1
 gelb  |  3 |    1
 rot   |  1 |    2
(3 rows)

Andreas

Ich dachte mir schon, daß “kurz und knackig” nicht spezifisch genug ist, und eine CASE-Lösung angeboten wird; aber Danke.
Da es viele Abfragen sind, und die Attribute oft mehr als 2 Ausprägungen haben, ist das jedes Mal manuelle Nacharbeit bzw. Anpassung.

kurz und knackig wäre:
/matrix2d
so wie man auch sonst verschiede Outputformate umschalten kann.

Ich schreibe mir ein Progrämmchen, so daß ich

psql -c "SELECT ..." demodb | tomatrix.sh

aufrufen kann.

Es gibt da noch im CONTRIB tablefunction mit crosstab()-Funktionen…

Andreas

Und hier ist mein externes Hilfsprogramm in Java:

import java.util.*;
import java.io.*;
/**
    ToMatrix

    @author Stefan Wagner
    @license GNU GPLv3 
    @version 0.1
    @date Fr 25. Jul 13:01:07 CEST 2008
*/
public class ToMatrix
{
    /** */
    public ToMatrix ()
    {
        try
        {
            BufferedReader cin = new BufferedReader (new InputStreamReader (System.in));
            String input;
            String [] attribut = new String [3];
            Set  <String> rows = new TreeSet <String> ();
            Set  <String> cols = new TreeSet <String> (); 
            Map <String, String> map = new HashMap <String, String> ();
            while ((input = cin.readLine ()) != null)
            {
                String [] token = input.split ("\\|");
                if (token.length == 3)
                {    
                    // header:
                    if (attribut[0] == null)
                    {
                        attribut[0] = token [0];
                        attribut[1] = token [1];
                        attribut[2] = token [2];
                    }
                    else 
                    {
                        rows.add (token [0]);
                        cols.add (token [1]);
                        map.put (token [0] + ":" + token [1], (token [2]));
                    }
                }
                // else: Dekoration "----------+----------+-------", Summary "(25 Zeilen)", leere Zeile
                // System.out.println ("debug: " + token [0]);
            }
            System.out.print (attribut[0] + "\\" + attribut[1]);
            for (String c : cols)
            {
                System.out.print ("\t" + c.trim ());
            }
            System.out.println ();
            for (String r : rows)
            {
                System.out.print (r.trim () + "\t");
                for (String c : cols)
                {
                    String value = map.get (r + ":" + c);
                    System.out.print (((value != null) ? value.trim () : "" ) + "\t");
                }
                System.out.println ();
            }
        }
        catch (IOException ioe) 
        {
            System.err.println (ioe); 
        }
    }

    /** */
    public static void main (String args[])
    {
        /* delimiter?
        String param = null;
        if (args.length == 1)
        {
            param = args[0];
        }
        //    usage ();
        //    System.exit (1);
        new ToMatrix (param);
        */
        new ToMatrix ();
    }

    /** 
    public static void usage ()
    {
        System.out.println ("Usage:\tjava ToMatrix param");
    }*/
}

Ja - schön wäre es, wenn man den in-Delimiter frei konfigurieren könnte, und den out-delimiter desgleichen, und pi pa po - erst mal sehen, ob das Programm zu mehr als einer Abfrage taugt.

So wird es benutzt:

psql -c " "SELECT bewahrg, gurt, COUNT (*) FROM fb GROUP BY 1, 2 ORDER BY 1, 2" demodb  | java ToMatrix

Die Ausgabe ist ein schickes:

bewahrg \ gurt         1    2    3    4    8    9
    649        4            8    3    
1    314    1    1        1    7    3    
2    255        2    1        5    2    
3    993        3    1        16    1    
9    67        3    1        10    3

Ja, da sind einige Null-Zellen dabei, aber so winschief sieht es in der Konsole schon nicht aus, und es läßt sich prima in die Tabellenkalkulation kopieren: Delimiter=Tabulatur.

Da freut sich OpenOffice. :slight_smile:

Bei Spaltennamen die einen Doppelpunkt enthalten könnte es krachen. :slight_smile:

Danke. Ist installiert. Mal sehen, ob ich mich zurechtfinde.

Ubuntu-8.04 bietet es ja für pg8.3 an.
Also habe ich es installiert, und einen DB-restart provoziert.
In den html-docs contrib gefunden. Beispiel versucht zu übertragen: FAIL.

Nochmal sorgfältig Seite 1 betrachtet - ah! Ich muß …/share/bla.sql laden! :slight_smile:
Mein übertragenes Beispiel probiert: FAIL.
Beispiel der html-doc probiert: SUCCESS.

Nun ja - ich versuche auch aggregierte Werte (count(*)) zu verarzten - ob es daran liegt?

SELECT * FROM crosstab('SELECT bewahrg, gurt, count (*) from fb GROUP BY 1, 2') AS ct (bewahrg text, gurt text, anz int4);
FEHLER:  invalid return type
DETAIL:  SQL rowid datatype does not match return rowid datatype.

bewahrg und gurt sind als varchar(3) definiert.

Mit

.. AS ct (bewahrg varchar(3), gurt varchar(3), anz int4);

erhalte ich den FEHLER: return and sql tuple descriptions are incompatible

Obwohl ich ja jetzt meine eigene Lösung habe wüßte ich gerne, wie es mit diesem contrib-code klappen sollte.
:slight_smile: