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…?
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)
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.
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
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.
Bei Spaltennamen die einen Doppelpunkt enthalten könnte es krachen.
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!
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.