Januar

leicht

Unter Verwendung der Tabelle nachweisverwaltung.n_nachweise sollen alle erfassten Dokumente für die bearbeiter Jana Dräger, Grit Sewekow, Markus Hentschel, Hendrik Reißland, Steffen Bakos und Andreas Breede sowie der zeit-raum der jeweiligen Erfassung folgendermaßen ausgegeben werden:

Bearbeiter      |Dokumente|von       |bis       
----------------+---------+----------+----------
Andreas Breede  |      337|2019-08-14|2019-09-27
Grit Sewekow    |    52946|2015-11-12|2022-01-11
Hendrik Reißland|       30|2018-05-29|2020-06-10
Jana Dräger     |      669|2020-01-22|2020-09-25
Markus Hentschel|       78|2015-12-21|2021-10-28
Steffen Bakos   |       65|2017-11-16|2019-06-27

Einen Zusatzpunkt gibt es für die Ausgabe und Sortierung der Spalte bearbeiter nach «Nachname, Vorname».

Lösung

SELECT concat_ws(
         ', ',
         split_part(bearbeiter, ' ', 2),
         split_part(bearbeiter, ' ', 1)) AS "Bearbeiter",  -- funktioniert nicht für mehr als einen Vor- bzw. Nachnamen
       count(*)                          AS "Dokumente",
       min(zeit)::date                   AS von,
       max(zeit)::date                   AS bis
  FROM nachweisverwaltung.n_nachweise
 WHERE bearbeiter IN ( 'Grit Sewekow','Jana Dräger','Markus Hentschel',
                       'Steffen Bakos','Hendrik Reißland','Andreas Breede')
 GROUP BY bearbeiter
 ORDER BY "Bearbeiter";

mittel

Unter Verwendung der Tabelle nachweisverwaltung.n_nachweise sollen alle erfassten Dokumente für die Jahre 2017 bis einschließlich 2021 für die bearbeiter Jana Dräger, Grit Sewekow, Markus Hentschel, Hendrik Reißland, Steffen Bakos und Andreas Breede folgendermaßen ausgegeben werden:

Jahr|Bakos|Breede|Dräger|Hentschel|Reißland|Sewekow
----+-----+------+------+---------+--------+-------
2017|   17|     0|     0|        3|       0|  11278
2018|    0|     0|     0|       25|       4|  11058
2019|   48|   337|     0|       45|      25|   5317
2020|    0|     0|   669|        1|       1|   4478
2021|    0|     0|     0|        3|       0|   4341

Lösung

/*
 *   If FILTER is specified, then only the input rows for which the filter_clause
 *   evaluates to true are fed to the aggregate function; other rows are discarded.
 *   https://www.postgresql.org/docs/9.4/sql-expressions.html#SYNTAX-AGGREGATES
 */
SELECT to_char(zeit, 'YYYY')::int                              AS "Jahr",
       count(*) FILTER (WHERE bearbeiter = 'Steffen Bakos')    AS "Bakos",      -- statt "count(*) FILTER (WHERE ..." geht auch count(CASE WHEN bearbeiter = '...' THEN 1 ELSE NULL END) AS "..."
       count(*) FILTER (WHERE bearbeiter = 'Andreas Breede')   AS "Breede",
       count(*) FILTER (WHERE bearbeiter = 'Jana Dräger')      AS "Dräger",
       count(*) FILTER (WHERE bearbeiter = 'Markus Hentschel') AS "Hentschel",
       count(*) FILTER (WHERE bearbeiter = 'Hendrik Reißland') AS "Reißland",
       count(*) FILTER (WHERE bearbeiter = 'Grit Sewekow')     AS "Sewekow"
  FROM nachweisverwaltung.n_nachweise
 WHERE bearbeiter IN ( 'Grit Sewekow','Jana Dräger','Markus Hentschel',
                       'Steffen Bakos','Hendrik Reißland','Andreas Breede' )
       AND zeit >= '2017-01-01'::timestamp AND zeit < '2022-01-01'::timestamp
 GROUP BY "Jahr"
 ORDER BY "Jahr";

schwer

Unter Verwendung der Tabelle nachweisverwaltung.n_nachweise soll die fortlaufende Summe für die Monate Januar 2020 bis einschließlich Dezember 2020 der monatlich erfassten Dokumente für die bearbeiter Jana Dräger und Grit Sewekow folgendermaßen ausgegeben werden:

Monat  |Dräger|Sewekow
-------+------+-------
01/2020|   219|    281
02/2020|   314|    585
03/2020|   319|   1057
04/2020|   515|   1573
05/2020|   666|   1877
06/2020|   666|   2448
07/2020|   666|   2881
08/2020|   666|   3073
09/2020|   669|   3669
10/2020|   669|   4091
11/2020|   669|   4270
12/2020|   669|   4478

Lösung

SELECT to_char(zeit, 'MM/YYYY')                               AS "Monat",
       sum(
         count(*) FILTER (WHERE bearbeiter = 'Jana Dräger')                 -- Aggregatfunktionen können innerhalb von Window-Funktionen verwendet werden
       ) OVER w::int                                          AS "Dräger",
       sum(
         count(*) FILTER (WHERE bearbeiter = 'Grit Sewekow')
       ) OVER w::int                                          AS "Sewekow"
  FROM nachweisverwaltung.n_nachweise
 WHERE bearbeiter IN ( 'Jana Dräger','Grit Sewekow' )
       AND zeit >= '2020-01-01'::timestamp AND zeit < '2021-01-01'::timestamp
 GROUP BY "Monat"
WINDOW w AS (ORDER BY to_char(zeit, 'MM/YYYY'))
 ORDER BY "Monat";

Februar

Als Datengrundlage für die Februar-Aufgaben muss zunächst eine temporäre Tabelle generiert werden:

SELECT setseed(0.52); -- Wird benötigt, damit alle dieselben random()-Daten generieren. 0.52 ist zufällig gewählt.
 
CREATE TEMPORARY TABLE scores (player,score) AS
SELECT (1 + random() * 4)::int,
       (1 + random() * 99)::int
  FROM generate_series(1,30) g;

Innerhalb der Session, in der die Tabelle angelegt wurde, lässt sie sich nun ganz normal aufrufen:

SELECT *
  FROM scores;

Temporäre Tabellen existieren nicht über eine Session hinaus. Sie existieren nicht Script- bzw. User-übergreifend. Sollte die Connection verloren gehen, muss die Tabelle erneut angelegt werden, um sie zu verwenden.

leicht

Der Spieler mit der höchsten Punktzahl ist zu ermitteln:

player|score
------|-----
     1|   96

Lösung

SELECT *
  FROM scores 
 ORDER BY score DESC 
 LIMIT 1;

mittel

Für jeden Spieler ist die höchste Punktzahl zu ermitteln:

player|score
------|-----
     1|   96
     2|   83
     3|   84
     4|   95
     5|   50

Lösung

SELECT player,
       max(score) AS score
  FROM scores
 GROUP BY player
 ORDER BY player;

schwer

Für jeden Spieler sind die 3 höchsten Punktzahlen zu ermitteln:

player|score
------|-----
     1|   96
     1|   47
     1|   12
     2|   83
     2|   77
     2|   60
     3|   84
     3|   46
     3|   19
     4|   95
     4|   93
     4|   87
     5|   50
     5|    7

Lösung

SELECT player,
       score
  FROM (SELECT player,
               score,
               rank() OVER (PARTITION BY player ORDER BY score DESC)
          FROM scores) foo
 WHERE rank <= 3
 ORDER BY player, score DESC;

März

leicht

Die Tabelle artikel

nr|bezeichnung|anzahl
--+-----------+------
 1|Bleistift  |     5
 2|Radiergummi|     3
 3|Lineal     |     2

… soll folgendermaßen ausgegeben werden:

bezeichnung|anzahl
-----------+------
Bleistift  |     1
Bleistift  |     1
Bleistift  |     1
Bleistift  |     1
Bleistift  |     1
Radiergummi|     1
Radiergummi|     1
Radiergummi|     1
Lineal     |     1
Lineal     |     1

Lösung

CREATE TEMPORARY TABLE artikel (nr,bezeichnung,anzahl) AS
VALUES (1::int,'Bleistift'::varchar,5::int),
       (2,'Radiergummi',3), (3,'Lineal',2);

 

mittel

Die Tabelle d

id|wert
--+----
 1|   3
 2|   8
 3|  12
 4|  15
 5|  19
 6|  22
 7|  28
 8|  33

… soll folgendermaßen ausgegeben werden:

low|high|dist
---+----+----
  0|   3|   3
  3|   8|   5
  8|  12|   4
 12|  15|   3
 15|  19|   4
 19|  22|   3
 22|  28|   6
 28|  33|   5
 33|  40|   7

Hinweise

  1. Man kann Tabellen auch mit sich selbst JOINen. Alle JOIN-Typen sind dabei erlaubt, auch die eher selten benutzten.
  2. PostgreSQL kennt Möglichkeiten mit NULL-Werten umzugehen. Du auch?

Lösung

CREATE TEMPORARY TABLE d (id,wert) AS
VALUES (1::int,3::int), (2,8),
       (3,12), (4,15), (5,19),
       (6,22), (7,28), (8,33);

 

schwer

Die Tabelle zeitraum

beginnt   |endet     
----------+----------
2021-12-23|2021-12-27
2021-12-25|2021-12-31
2021-12-31|2022-01-03
2022-01-04|2022-01-05
2022-01-07|2022-01-12
2022-01-11|2022-01-15

… soll ohne überlagernde Zeiträume ausgegeben werden:

beginnt   |endet     
----------+----------
2021-12-23|2022-01-03
2022-01-04|2022-01-05
2022-01-07|2022-01-15

Hinweise

  1. Schritt 1: beginnt und endet zu zeitpunkt zusammenfassen und eine weitere Spalte ereignis erzeugen mit den Werten +1 für beginnt und -1 für endet

Lösung

CREATE TEMPORARY TABLE zeitraum (beginnt,endet) AS
VALUES ('2021-12-23'::date,'2021-12-27'::date),
       ('2021-12-25','2021-12-31'),
       ('2021-12-31','2022-01-03'),
       ('2022-01-04','2022-01-05'),
       ('2022-01-07','2022-01-12'),
       ('2022-01-11','2022-01-15');

 

April

leicht

Aus einer Stichprobe d mit 100 annähernd normalverteilten Werten v sind folgende statistische Lageparameter zu berechnen:

                                                          +------------------------------+
                                                          | -> 1 Zusatzpunkt             |
                                                          |                              |
Minimum|Maximum|Mittelwert|Standardabweichung|Median|Modus|unteres Quartil|oberes Quartil|
-------+-------+----------+------------------+------+-----+---------------+--------------|
    -32|    192|     95.91|            49.918|  98.0|  160|           67.0|         138.5|
                                                          |                              |
                                                          +------------------------------+

Lösung

CREATE TEMPORARY TABLE d (v) AS
SELECT (( random() + random() + random() + random()
          + random() + random() + random() + random()
          + random() + random() + random() + random()
          - 6) * 49 + 100)::int
  FROM setseed(0),
       generate_series(1,100);

 

mittel

Die Tabelle d enthält Duplikate in v:

i |v
--+-
 1|0
 2|0
 3|0
 4|2
 5|4
 6|1
 7|1
 8|5
 9|5
10|5
11|2
12|8
13|9
14|6
15|6
16|1
17|8
18|0
19|3
20|3

Es ist eine DELETE-Anweisung zu schreiben, welche alle Duplikate entfernt und die Datensätze mit dem jeweils kleinsten i behält.

Lösung

CREATE TEMPORARY TABLE d (i,v) AS
SELECT i, (10 * random())::int AS v
  FROM setseed(0),
       generate_series(1,20) i;

 

schwer

Für Tabelle d sind alle Permutationen ohne Wiederholung zu erzeugen:

perm
---- ┌--┐   ┌--┐   ┌--┐
ABCD | BACD | CABD | DABC
ABDC | BADC | CADB | DACB
ACBD | BCAD | CBAD | DBAC
ACDB | BCDA | CBDA | DBCA
ADBC | BDAC | CDAB | DCAB
ADCB | BDCA | CDBA | DCBA
 └---┘  └---┘  └---┘

Lösung

CREATE TEMPORARY TABLE d (v) AS
VALUES ('A'),('B'),('C'),('D');