Aufgabe 3 - SQL-Abfragen · Abitur NRW Informatik LK · Nachtermin 2023
Thema: SQL-Abfragen · Aus der Prüfung LK · Nachtermin (2023)
Aufgabenstellung
Sachkontext: E-Auto-Ladesäulen-App
Fahrzeuge mit Verbrennungsmotor setzen frei, das erheblich zum Klimawandel beiträgt. Daher strebt Deutschland an, den Straßenverkehr auf Elektrofahrzeuge (E-Autos) zu verlagern. Zu diesem Zweck entstehen bundesweit an zahlreichen Standorten Ladesäulen für E-Autos.
Die Ladesäulen werden von unterschiedlichen Betreibergesellschaften betrieben. Wer sein E-Auto unterwegs laden möchte, muss sich dafür jeweils bei der Betreibergesellschaft der betreffenden Ladesäule registrieren.
Eine Firma stellt eine App bereit, mit der man E-Autos an Ladesäulen verschiedener Betreibergesellschaften laden kann. Dazu hinterlegt die Fahrerin oder der Fahrer in der App eine Kreditkarte und scannt vor dem Ladevorgang den QR-Code der Ladesäule. Anschließend leitet die Firma die Zahlung für den Ladevorgang an die Betreibergesellschaft der Ladesäule weiter.
Die Daten der Firma liegen in einer relationalen Datenbank. Abbildung 1 zeigt einen Teil der Modellierung.
Hinweis: Das Attribut Menge gibt die bei dem Ladevorgang übertragene Energiemenge in kWh an.
Datenbankschema
Das in Abbildung 2 gezeigte Datenbankschema setzt die Teilmodellierung um und wird im Weiteren zugrunde gelegt. Beispieldaten zu diesem Schema finden sich im Anhang.
Implementationsdiagramm der App
Die App soll die Standorte aller Ladesäulen eines bestimmten Steckertyps innerhalb eines vorgegebenen Umkreises um die aktuelle Position der Benutzerin bzw. des Benutzers anzeigen. Abbildung 3 enthält als Implementationsdiagramm einen Ausschnitt der App-Modellierung.
Anlage: Ausschnitt aus den Beispieldaten zum Datenbankschema
Kunde
ID · Name · Emailadresse · Kreditkartennummer
1 · Albert Anger · a@anger.de · 1234-5678-9000-4321
2 · Birte Bolweg · b@bolweg.de · 1212-3434-5656-7878
3 · Christa Ciunta · c@ciunta.de · 1111-2222-3333-4444
Betreiber
Name · Adresse · Bank · Kontonummer
E-Werke Sauerland · Industrieweg 9, 59755 Arnsberg · Voltbank · 987654321
Pottpower · Werkstraße 3, 45219 Essen · Amperekasse · 232323232
Rheinstrom · An der Fabrik 7, 40597 Düsseldorf · Wattsparkasse · 123456789
Westfalenkraft · Gewerbegasse 8, 48143 Münster · Amperekasse · 100000001
Ladesaeule
ID · BetreiberName · Standort · Steckertyp · maximaleLadeleistung
1 · Rheinstrom · Sonnenhang · Typ 2 · 22
2 · Pottpower · Sonnenhang · CCS · 150
3 · Westfalenkraft · Stausee · CCS · 300
4 · Pottpower · Windwinkel · CHAdeMO · 50
5 · Rheinstrom · Windwinkel · Typ 1 · 7
6 · Pottpower · Windwinkel · CCS · 150
7 · Rheinstrom · Windwinkel · CCS · 150
8 · Westfalenkraft · Grüner Strom · Typ 2 · 11
9 · Westfalenkraft · Grüner Strom · Typ 2 · 11
hatGeladen
KundeID · LadesaeuleID · Zeitstempel · Menge
1 · 3 · 2023-03-21-14-27 · 35
1 · 2 · 2023-03-28-07-02 · 21
3 · 8 · 2023-03-30-22-54 · 47
1 · 6 · 2023-04-02-18-43 · 29
3 · 1 · 2023-04-06-09-00 · 38
Anhang: Dokumentationen der verwendeten Klassen
Die Klasse LadeApp
Ein Objekt der Klasse LadeApp stellt der Benutzerin bzw. dem Benutzer auf einem mobilen Endgerät die Funktionen des Ladesystems zur Verfügung. Hier sind nur die für die Bearbeitung des Aufgabenteils e) relevanten Methoden dokumentiert.
Dokumentation der Klasse LadeApp
LadeApp()
Ein Objekt der Klasse LadeApp wird initialisiert.
List<String> gibStandorteImUmkreis(double pEntfernung, String pSteckertyp)
Die Anfrage gibt eine Liste mit den Namen von allen passenden Standorten von Ladesäulen zurück. Dabei gilt:
Die Liste enthält alle Standorte aus der Datenbank, an denen mindestens eine Ladesäule mit dem im Parameter pSteckertyp übergebenen Steckertyp zur Verfügung steht und
bei denen die Entfernung von der aktuellen Position der Benutzerin bzw. des Benutzers maximal den in dem Parameter pEntfernung in km übergebenen Wert hat.
Wenn ein Fehler in der Datenbankverbindung auftritt, wird eine leere Liste zurückgegeben.
double gibEntfernungZurAktuellenPosition(String pStandort)
Es wird die Distanz in km zwischen der aktuellen Position der Benutzerin bzw. des Benutzers und dem im Parameter pStandort übergebenen Standort ermittelt.
Die generische Klasse List
Objekte der generischen Klasse List verwalten beliebig viele, linear angeordnete Objekte vom Typ ContentType. Auf höchstens ein Listenobjekt, aktuelles Objekt genannt, kann jeweils zugegriffen werden. Wenn eine Liste leer ist, vollständig durchlaufen wurde oder das aktuelle Objekt am Ende der Liste gelöscht wurde, gibt es kein aktuelles Objekt. Das erste oder das letzte Objekt einer Liste kann durch einen Auftrag zum aktuellen Objekt gemacht werden. Außerdem kann das dem aktuellen Objekt folgende Listenobjekt zum neuen aktuellen Objekt werden.
Das aktuelle Objekt kann gelesen, verändert oder gelöscht werden. Außerdem kann vor dem aktuellen Objekt ein Listenobjekt eingefügt werden.
Dokumentation der Klasse List<ContentType>
List()
Eine leere Liste wird erzeugt.
boolean isEmpty()
Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthält, sonst liefert sie den Wert false.
boolean hasAccess()
Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt, sonst liefert sie den Wert false.
void next()
Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses nicht das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in der Liste folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach Ausführung des Auftrags kein aktuelles Objekt, d. h., hasAccess() liefert den Wert false.
void toFirst()
Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.
void toLast()
Falls die Liste nicht leer ist, wird das letzte Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.
ContentType getContent()
Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das aktuelle Objekt zurückgegeben. Andernfalls (hasAccess() == false) gibt die Anfrage den Wert null zurück.
void setContent(ContentType pContent)
Falls es ein aktuelles Objekt gibt (hasAccess() == true) und pContent ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst bleibt die Liste unverändert.
void append(ContentType pContent)
Ein neues Objekt pContent wird am Ende der Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt (hasAccess() == false). Falls pContent gleich null ist, bleibt die Liste unverändert.
void insert(ContentType pContent)
Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird ein neues Objekt pContent vor dem aktuellen Objekt in die Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Falls die Liste leer ist und es somit kein aktuelles Objekt gibt (hasAccess() == false), wird pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt. Falls es kein aktuelles Objekt gibt (hasAccess() == false) und die Liste nicht leer ist oder pContent == null ist, bleibt die Liste unverändert.
void concat(List<ContentType> pList)
Die Liste pList wird an die Liste angehängt. Anschließend wird pList eine leere Liste. Das aktuelle Objekt bleibt unverändert. Falls es sich bei der Liste und pList um dasselbe Objekt handelt, pList == null oder eine leere Liste ist, bleibt die Liste unverändert.
void remove()
Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das aktuelle Objekt gelöscht und das Objekt hinter dem gelöschten Objekt wird zum aktuellen Objekt. Wird das Objekt, das am Ende der Liste steht, gelöscht, gibt es kein aktuelles Objekt mehr (hasAccess() == false). Wenn die Liste leer ist oder es kein aktuelles Objekt gibt (hasAccess() == false), bleibt die Liste unverändert.
Die Klasse DatabaseConnector
Ein Objekt der Klasse DatabaseConnector ermöglicht die Abfrage und Manipulation einer relationalen Datenbank. Beim Erzeugen des Objekts wird eine Datenbankverbindung aufgebaut, sodass anschließend SQL-Anweisungen an diese Datenbank gerichtet werden können.
Dokumentation der Klasse DatabaseConnector
DatabaseConnector(String pIP, int pPort, String pDatabase, String pUsername, String pPassword)
Ein Objekt vom Typ DatabaseConnector wird erstellt, und eine Verbindung zur Datenbank wird aufgebaut. Mit den Parametern pIP und pPort werden die IP-Adresse und die Port-Nummer übergeben, unter denen die Datenbank mit Namen pDatabase zu erreichen ist. Mit den Parametern pUsername und pPassword werden Benutzername und Passwort für die Datenbank übergeben.
void executeStatement(String pSQLStatement)
Der Auftrag schickt den im Parameter pSQLStatement enthaltenen SQL-Befehl an die Datenbank ab.
Handelt es sich bei pSQLStatement um einen SQL-Befehl, der eine Ergebnismenge liefert, so kann dieses Ergebnis anschließend mit der Methode getCurrentQueryResult abgerufen werden.
QueryResult getCurrentQueryResult()
Die Anfrage liefert das Ergebnis des letzten mit der Methode executeStatement an die Datenbank geschickten SQL-Befehls als Objekt vom Typ QueryResult zurück.
Wurde bisher kein SQL-Befehl abgeschickt oder ergab der letzte Aufruf von executeStatement keine Ergebnismenge (z. B. bei einem INSERT-Befehl oder einem Syntaxfehler), so wird null geliefert.
String getErrorMessage()
Die Anfrage liefert null oder eine Fehlermeldung, die sich jeweils auf die letzte zuvor ausgeführte Datenbankoperation bezieht.
void close()
Die Datenbankverbindung wird geschlossen.
Die Klasse QueryResult
Ein Objekt der Klasse QueryResult stellt die Ergebnistabelle einer Datenbankanfrage mithilfe der Klasse DatabaseConnector dar. Objekte dieser Klasse werden nur von der Klasse DatabaseConnector erstellt. Die Klasse verfügt über keinen öffentlichen Konstruktor.
Dokumentation der Klasse QueryResult
String[][] getData()
Die Anfrage liefert die Einträge der Ergebnistabelle als zweidimensionales Feld vom Typ String. Der erste Index des Feldes stellt die Zeile und der zweite die Spalte dar (d. h. String[zeile][spalte]).
String[] getColumnNames()
Die Anfrage liefert die Bezeichner der Spalten der Ergebnistabelle als Feld vom Typ String zurück.
String[] getColumnTypes()
Die Anfrage liefert die Typenbezeichnung der Spalten der Ergebnistabelle als Feld vom Typ String zurück. Die Bezeichnungen entsprechen den Angaben in der Datenbank.
int getRowCount()
Die Anfrage liefert die Anzahl der Zeilen der Ergebnistabelle als int.
int getColumnCount()
Die Anfrage liefert die Anzahl der Spalten der Ergebnistabelle als int.
Teilaufgabe b)
Es sollen die folgenden Informationen aus der Datenbank abgefragt werden:
(i)
Für den Standort Sonnenhang soll eine Liste ausgegeben werden, die alle auftretenden Kombinationen aus Steckertyp und maximaler Ladeleistung enthält, wobei keine Kombination mehrfach erscheinen darf. Die Sortierung erfolgt zuerst absteigend nach der maximalen Ladeleistung, anschließend aufsteigend nach der Bezeichnung des Steckertyps. [4 Punkte]
(ii)
Gesucht ist eine Liste aller Kundinnen und Kunden, die an Ladesäulen des Betreibers Pottpower Strom geladen haben. Zu jeder Person sollen der Name, die E-Mail-Adresse und die gesamte geladene Energiemenge angezeigt werden. Die Sortierung soll absteigend nach der Gesamtlademenge erfolgen. [5 Punkte]
Teilaufgabe c)
Gegeben ist die folgende SQL-Anweisung:
1 SELECT Ladesaeule.Standort, COUNT(*) AS Anzahl
2 FROM Ladesaeule
3 WHERE Ladesaeule.ID NOT IN (
4 SELECT hatGeladen.LadesaeuleID
5 FROM hatGeladen
6 WHERE Zeitstempel BETWEEN '2023-03-01-00-00'
7 AND '2023-03-31-23-59'
8)
9 GROUP BY Ladesaeule.Standort
10 ORDER BY Anzahl DESC
c.1)
Analysieren und erläutern Sie zuerst die Unterabfrage, die sich in den Zeilen 4 bis 7 befindet. [4 Punkte]
c.2)
Analysieren und erläutern Sie die SQL-Anweisung als Ganzes. [4 Punkte]
c.3)
Erläutern Sie im Sachzusammenhang, welche Information mit der gesamten SQL-Anweisung bestimmt wird. [2 Punkte]
Teilaufgabe e)
Die App soll die Standorte aller Ladesäulen anzeigen können, die einen bestimmten Steckertyp haben und innerhalb eines festgelegten Umkreises um die aktuelle Position der Nutzerin bzw. des Nutzers liegen. Abbildung 3 zeigt als Implementationsdiagramm einen Ausschnitt der Modellierung der App.
Ein Softwareentwickler hat die Methode gibStandorteImUmkreis bereits teilweise bearbeitet:
1 public List<String> gibStandorteImUmkreis(double pEntfernung,
2 String pSteckertyp) {
3 String sql = "SELECT DISTINCT Standort "
4 + "FROM Ladesaeule "
5 + "WHERE Ladesaeule.Steckertyp = "
6 + "'" + pSteckertyp + "';";
7
8 datenbank.executeStatement(sql);
9
10 QueryResult qr = datenbank.getCurrentQueryResult();
11 List<String> ergebnis = new List<String>();
12 if (qr != null) {
13 // TODO: Hier weiterarbeiten!!!
14 }
15 return ergebnis;
16 }
e.1)
Analysieren Sie den unvollständigen Programmtext der Methode gibStandorteImUmkreis und beurteilen Sie bezüglich aller drei Punkte der Methodendokumentation, ob der Entwickler diese schon umgesetzt hat. [4 Punkte]
e.2)
Entwickeln und beschreiben Sie ein algorithmisches Verfahren, mit dem der vorliegende Programmtext so erweitert wird, dass alle Punkte der Methodendokumentation erfüllt sind. [3 Punkte]
e.3)
Vervollständigen Sie den Programmtext der Methode gibStandorteImUmkreis so, dass alle Punkte der Methodendokumentation umgesetzt werden (Ersatz für Zeile 13). [4 Punkte]

Lösung
Nach den offiziellen Korrekturhinweisen
b) (i) Für den Standort Sonnenhang soll eine Liste ausgegeben werden, die alle auftretenden Kombinationen aus Steckertyp und maximaler Ladeleistung enthält, wobei keine Kombination mehrfach erscheinen darf. Die Sortierung erfolgt zuerst absteigend nach der maximalen Ladeleistung, anschließend aufsteigend nach der Bezeichnung des Steckertyps.
Lösung: ```sql SELECT DISTINCT Steckertyp, maximaleLadeleistung FROM Ladesaeule WHERE Standort = 'Sonnenhang' ORDER BY maximaleLadeleistung DESC, Steckertyp ASC; ```
b) (ii) Gesucht ist eine Liste aller Kundinnen und Kunden, die an Ladesäulen des Betreibers Pottpower Strom geladen haben. Zu jeder Person sollen der Name, die E-Mail-Adresse und die gesamte geladene Energiemenge angezeigt werden. Die Sortierung soll absteigend nach der Gesamtlademenge erfolgen.
Lösung: ```sql SELECT Kunde.Name, Kunde.Emailadresse, SUM(hatGeladen.Menge) AS Menge FROM Kunde INNER JOIN hatGeladen ON Kunde.ID = hatGeladen.KundeID INNER JOIN Ladesaeule ON hatGeladen.LadesaeuleID = Ladesaeule.ID WHERE Ladesaeule.BetreiberName = 'Pottpower' GROUP BY Kunde.ID ORDER BY Menge DESC; ```
c) Analysieren und erläutern Sie zuerst die Unterabfrage, die sich in den Zeilen 4 bis 7 befindet.
Lösung: Die Unterabfrage in den Zeilen 4 bis 7 ermittelt aus der Relation hatGeladen die IDs aller Ladesäulen, an denen im März 2023 mindestens ein Ladevorgang stattgefunden hat.
c) Analysieren und erläutern Sie die SQL-Anweisung als Ganzes.
Lösung: Durch das NOT IN in Zeile 3 werden durch die gesamte SQL-Anweisung anschließend aus der Relation Ladesaeule die Datensätze der Ladesäulen ermittelt, die nicht in der Ergebnistabelle der Unterabfrage in den Zeilen 4 – 7 aufgeführt sind. Die Datensätze der Ladesäulen werden in Zeile 9 nach dem Standort gruppiert. In der Ergebnistabelle werden dann die Namen der Standorte zusammen mit der Anzahl der Datensätze ausgegeben. Das wird durch die Aggregatfunktion COUNT erreicht.
c) Erläutern Sie im Sachzusammenhang, welche Information mit der gesamten SQL-Anweisung bestimmt wird.
Lösung: Insgesamt wird eine Liste aller Standorte jeweils mit der Anzahl der Ladesäulen an den Standorten ausgegeben, an denen im März 2023 kein Ladevorgang stattgefunden hat.
e) Analysieren Sie den unvollständigen Programmtext der Methode gibStandorteImUmkreis und beurteilen Sie bezüglich aller drei Punkte der Methodendokumentation, ob der Entwickler diese schon umgesetzt hat.
Lösung: 1. Punkt (passende Steckertypen): Berücksichtigt. In der SQL-Anweisung wird der Parameter pSteckertyp in den WHERE-Teil eingebaut, sodass nur Standorte mit dem gewünschten Steckertyp selektiert werden. 2. Punkt (Umkreis / maximale Entfernung): Nicht berücksichtigt. Der Parameter pEntfernung wird im vorliegenden Programmtext noch gar nicht verwendet. 3. Punkt (Fehlerbehandlung / leere Liste bei Datenbankfehler): Berücksichtigt. Durch die Verzweigung if (qr != null) wird geprüft, ob die Abfrage ein Ergebnis geliefert hat; andernfalls wird die leer initialisierte Liste ergebnis unverändert zurückgegeben.
e) Entwickeln und beschreiben Sie ein algorithmisches Verfahren, mit dem der vorliegende Programmtext so erweitert wird, dass alle Punkte der Methodendokumentation erfüllt sind.
Lösung: Da noch die Anforderung in Bezug auf die Entfernung der Standorte von Ladesäulen von der aktuellen Position der Nutzerin bzw. des Nutzers berücksichtigt werden muss, werden die Zeilen der Ergebnistabelle in dem Objekt der Klasse QueryResult in der lokalen Variablen qr in einer Zählschleife durchlaufen. Zu jedem Standort, der in der Ergebnistabelle aufgeführt ist, wird unter Verwendung der Hilfsmethode gibEntfernungZurAktuellenPosition geprüft, ob die Distanz zum aktuellen Standort der Nutzerin bzw. des Nutzers kleiner ist als der im Parameter pEntfernung übergebene Wert bzw. gleich. Ist das der Fall, wird der aktuelle Standort an die Ergebnisliste angehängt.
e) Vervollständigen Sie den Programmtext der Methode gibStandorteImUmkreis so, dass alle Punkte der Methodendokumentation umgesetzt werden.
Lösung: ```java for (int i = 0; i < qr.getRowCount(); i++) { String einStandort = qr.getData()[i][0]; if (gibEntfernungZurAktuellenPosition(einStandort) <= pEntfernung) { ergebnis.append(einStandort); } } ```
Die ausführliche Erklärung Schritt für Schritt (mit KI) gibt es mit Premium. Premium
Löse sie direkt hier: automatische Korrektur, Hinweise und Lösung Schritt für Schritt.
‹ Aufgabe 3 - SQL-Abfragen · LK · Haupttermin · Weiterbildungskolleg 2023 · Aufgabe 3 - SQL-Abfragen · GK · Haupttermin 2022 ›
Mehr Aufgaben zu SQL-Abfragen
- Aufgabe 3 - SQL-Abfragen · GK · Haupttermin 2023
- Aufgabe 3 - SQL-Abfragen · GK · Haupttermin · Weiterbildungskolleg 2023
- Aufgabe 3 - SQL-Abfragen und Auswertung in Java · GK · Nachtermin 2023
- Aufgabe 3 - SQL-Abfragen · LK · Haupttermin 2023
- Aufgabe 3 - SQL-Abfragen · LK · Haupttermin · Weiterbildungskolleg 2023
- Aufgabe 3 - SQL-Abfragen · GK · Haupttermin 2022
- Aufgabe 3 - SQL-Abfragen · GK · Nachtermin 2022
- Aufgabe 3 - SQL-Abfragen · LK · Haupttermin 2022
- Aufgabe 3 - SQL-Abfragen · LK · Nachtermin 2022
- Aufgabe 3 - SQL-Abfragen · GK · Haupttermin 2021