Eine Bundesligatabelle und SQLite

1. Aufgabe

Wir kommen in dieser Aufgabe auf das Erstellen einer Tabelle für eine Sportart wie Fußball, Handball etc. zu sprechen. Um die notwendigen Daten zur Berechnung der aktuellen Tabelle dauerhaft zu halten, ist für deren Ablage ein Datenbanksystem die erste Wahl. Im .NET-Framework gibt es hierzu gleich mehrere Optionen: ADO.NET, LINQ to SQL, Entity Framework, usw. Interessanterweise greife ich auf keines dieser .NET-Bordmittel zurück, sondern habe ein dediziertes, .NET-fremdes Public Domain Datenbanksystem namens SQLite ausgewählt, siehe http://www.sqlite.org/. Der Grund hierfür ist sehr einfacher Natur: Da ich eine Fallstudie zum Thema Android und Datenbanken in Vorbereitung habe und SQLite – unter anderem – in Android integriert ist, wollte ich das Datenbankhandlung mit ein- und demselben relationalen Datenbanksystem abhandeln.

Prinzipiell ist SQLite eine C-Bibliothek, die einen eingebetteten Datenbankserver enthält. Programme, die SQLite verwenden, können SQL-Datenbanken ohne einen separaten RDBMS-Prozess, also ohne separaten Datenbankserver nutzen. SQLite ist keine client-seitige Bibliothek, die zur Verbindung mit einem großen Datenbankserver genutzt wird: SQLite ist der Server. Die SQLite-Bibliothek liest und schreibt direkt von und auf eine einzelne Datenbankdatei auf der Festplatte. Für viele populäre Programmiersprachen wie Java oder C# gibt es entsprechende Wrapper-Klassen, so dass man nicht nur auf C festgelegt ist. In dieser Fallstudie setze ich die so genannte System.Data.SQLite-Klassenbibliothek ein, einen kostenlosen C#-/ADO.NET-Wrapper. Zur Installation des Wrappers finden sich zahlreiche Hinweise im Netz.

Erstellen Sie eine einfache WPF-Anwendung, die die Ablage des Datenbestands für eine Liga-Tabelle auf Basis des SQLite-Datenbanksystems durchführt. Eine mögliche Oberfläche der Anwendung finden Sie in Abbildung 1 vor:

Berechnung einer Bundesligatabelle mit SQL.

Abbildung 1. Berechnung einer Bundesligatabelle mit SQL.


Mittels SQL-Anweisungen soll es möglich sein, an Hand zweier Tabellen mit allen Informationen zu den beteiligten Mannschaften und vorhandenen Spielresultaten eine weitere, temporäre Tabelle zu erzeugen, die die aktuelle Ligatabelle repräsentiert. Die WPF-Anwendung selbst dient nur dem Zweck, mit einfachen Hilfsmitteln die unterschiedlichen SQL-Anweisungen anzustoßen. Zur Visualisierung der Ligatabelle sollte ein DataGrid-Steuerelement zum Einsatz kommen.

2. Lösung

 

Bevor wir auf die Umsetzung der Aufgabenstellung eingehen, durchlaufen wir einen kleinen Exkurs in SQL, um den Datenbestand einer Liga während des Spielbetriebs samt der Erstellung einer Ligatabelle in SQL zu betrachten. Dazu bedienen wir uns eines SQLite Datenbank Browser Tools, mit dessen Hilfe sich eine SQLite-Datenbankdatei erzeugen, entwerfen und modifizieren lässt.

Zunächst einmal benötigen wir für eine Liga in der Datenbank zwei Tabellen TEAMS und GAMES: In der Tabelle TEAMS sind alle Information zu einer Mannschaft abgelegt, wie etwa der Name der Mannschaft und die Stadt, in der sie beheimatet ist. Weitere Informationen wie der Stadionname, indem die die Heimspiele ausgetragen werden, die Anzahl der Vereinsmitglieder usw. können optional ergänzt werden. Zum Anlegen dieser Tabelle verwenden wir die folgende SQL-CREATE-Anweisung:

CREATE TABLE IF NOT EXISTS TEAMS (
    ID INTEGER PRIMARY KEY NOT NULL,
    NAME TEXT NOT NULL,
    CITY TEXT NOT NULL
);

Im Laufe einer Spielsaison findet eine Reihe von Spielen dieser Mannschaften gegeneinander statt. Die Anzahl der erzielten und erhaltenen Tore entscheidet über das Resultat des Spiels. Es können Spiele auch ausfallen und zu einem anderen Zeitpunkt nachgeholt werden. Aus diesem Grund ist jedem Spiel ein Spieltag zugeordnet, an dem das Spiel normalerweise stattfindet. In der Tabelle GAMES werden pro Spiel der Spieltag, die IDs der beteiligten Mannschaften (Fremdschlüssel in Bezug auf Tabelle TEAMS) und die Anzahl der erzielten und erhaltenen Tore (aus Sicht der Heimmannschaft) eingetragen:

CREATE TABLE IF NOT EXISTS GAMES (
    ID INTEGER PRIMARY KEY AUTOINCREMENT,
    MATCHDAY  INTEGER NOT NULL,
    TEAMHOME  INTEGER NOT NULL,
    TEAMAWAY  INTEGER NOT NULL,
    GOALSHOME INTEGER NOT NULL,
    GOALSAWAY INTEGER NOT NULL
);

Das Befüllen der beiden Tabellen erfolgt mit der SQL-Anweisung INSERT. Die folgenden Anweisungsfolgen können nur einen kleinen Ausschnitt aus der Menge aller SQL-Anweisungen vermitteln, der nötig wäre, um die Resultate der Fußballbundesliga 2013/14 komplett in SQL abzubilden:

INSERT INTO TEAMS (ID, NAME,CITY) VALUES (0, 'Hertha BSC', 'Berlin');
INSERT INTO TEAMS (ID, NAME,CITY) VALUES (1, 'Borussia Dortmund', 'Dortmund');
INSERT INTO TEAMS (ID, NAME,CITY) VALUES (2, 'Bayer Leverkusen', 'Leverkusen');
...

und

INSERT INTO GAMES (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) VALUES (1, 3, 14, 3, 1);
INSERT INTO GAMES (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) VALUES (1, 10, 9, 2, 2);
...

Ein Auslesen aller Daten in den zwei Tabellen TEAMS und GAMES kann mit der SQL-Anweisung SELECT erfolgen:

SELECT * FROM TEAMS

bzw.

SELECT * FROM GAMES

Nach jedem absolvierten Spiel ist die Tabelle GAMES entsprechend um das Spielresultat zu ergänzen. Um nun zu einer Ligatabelle zu gelangen, sind bereits alle notwendigen Daten im Datenbestand vorhanden. Es ist nur noch das Problem zu lösen, wie es mit Hilfe der beiden Tabellen TEAMS und GAMES sowie einer geeigneten SQL-Anweisung möglich ist, eine Ligatabelle zu generieren. Ich würde diese Fragestellung nicht als ganz einfach bezeichnen, wir zerlegen sie daher im Folgenden in mehrere Einzelschritte. Eine unmittelbare Betrachtung des Endresultats könnte möglicherweise doch etwas zu Irritationen des Betrachters führen, da dieses etwas umfangreich ist.

Zu diesem Zweck verinnerlichen wir zunächst einmal die Erkenntnis, dass ein Spielresultat, etwa der Form 1. FC Nürnberg gegen FC Bayern München 2 zu 1 tabellenrelevante Informationen für zwei Mannschaften enthält. Zum einen die Information, dass Nürnberg 3 Punkte für dieses Spiel erhält (und dabei zwei Tore geschossen hat) sowie Bayern München keinen Punkt für dieses Spiel verbuchen kann, allerdings ein erzieltes Tor mehr hat. Um zu einer Ligatabelle zu kommen, empfiehlt es sich also, aus einem Spielresultat zwei neue Datensätze zu erzeugen, jeweils einen pro beteiligter Mannschaft mit allen Information aus Sicht dieser Mannschaft. Damit betrachten wir im ersten Schritt die Bildung einer neuen (temporären) Tabelle aus dem Blickwinkel, welche Mannschaft aus ihrer Sicht für ein Spiel wie viele Punkte bekommt und welches Spielresultat eingefahren hat (Anzahl der erzielten und erhaltenen Tore):

Schritt 1: Erzeugung einer Grundtabelle

SELECT
  GAMES.TEAMHOME AS TEAM, GAMES.GOALSHOME AS GOALSSELF,
  GAMES.GOALSAWAY AS GOALSOTHER FROM GAMES
UNION ALL
SELECT
  GAMES.TEAMAWAY AS TEAM, GAMES.GOALSAWAY AS GOALSSELF,
  GAMES.GOALSHOME AS GOALSOTHER FROM GAMES

Das Resultat dieser SQL-Anweisung betrachten wir mit dem SQLite Database Browser in Abbildung 2:

Erzeugung einer Grundtabelle.

Abbildung 2. Erzeugung einer Grundtabelle.


Bei drei in der Tabelle GAMES abgelegten Spieltagen zu 9 Spielen erwarten wir zwei Mal 27, also 54 Zeilen in der Resultattabelle, wovon wir uns im Ausgabefenster des SQLite Browser Tools überzeugen können.

Nachteilig im ersten Schritt ist der Umstand, dass die beteiligten Mannschaften mit ihrem Primärschlüssel in Bezug auf die Tabelle TEAMS aufgeführt sind. Mit Hilfe einer SQL-JOIN-Anweisung lassen sich die IDs (Fremdschlüssel) der Mannschaften auch zu Gunsten ihrer symbolischen Namen ersetzen. Das bringt zwar im Augenblick nicht sehr viel in Bezug auf unser gestecktes Ziel der Generierung einer Ligatabelle, aber zu Demonstrationszwecken können wir das ja Mal zwischendurch einschieben.

Schritt 2: Verknüpfung einer temporären Tabelle mit einer statischen Tabelle

Um die Primärschlüssel der beteiligten Mannschaften durch ihren Mannschaftsnamen zu ersetzen, benötigen wir eine JOIN-Anweisung:

SELECT TEAMS.NAME AS TEAMNAME, GOALSSELF, GOALSOTHER
FROM (
    SELECT
        GAMES.TEAMHOME AS TEAMID, GAMES.GOALSHOME AS GOALSSELF,
        GAMES.GOALSAWAY AS GOALSOTHER FROM GAMES
    UNION ALL
    SELECT
        GAMES.TEAMAWAY AS TEAMID, GAMES.GOALSAWAY AS GOALSSELF,
        GAMES.GOALSHOME AS GOALSOTHER FROM GAMES
) AS TABLEENTRIES
JOIN TEAMS ON TABLEENTRIES.TEAMID = TEAMS.ID

Das Ergebnis dieser SQL-Anweisung finden Sie in Abbildung 3 vor:

Verknüpfung einer temporären Tabelle mit einer statischen Tabelle.

Abbildung 3. Verknüpfung einer temporären Tabelle mit einer statischen Tabelle.


Schritt 3: Eine Tabelle sortieren

Wir kehren wieder zurück zum ersten Schritt und gehen nun den Aspekt des Sortierens einer Tabelle an. Noch haben wir nicht die Information Erzielte Punkte pro Spiel generiert. Aus diesem Grund sortieren wir den Datenbestand aus Schritt 1 zunächst einmal in Bezug auf den Fremdschlüssel der Mannschaften. Um Zeilen einer SQL-Tabelle zu sortieren, gibt es die Anweisung ORDER BY:

SELECT * FROM (
    SELECT
        GAMES.TEAMHOME AS TEAM, GAMES.GOALSHOME AS GOALSSELF,
        GAMES.GOALSAWAY AS GOALSOTHER FROM GAMES
    UNION ALL
    SELECT
        GAMES.TEAMAWAY AS TEAM, GAMES.GOALSAWAY AS GOALSSELF,
        GAMES.GOALSHOME AS GOALSOTHER FROM GAMES
)
ORDER BY TEAM ASC
Eine Tabelle sortieren.

Abbildung 4. Eine Tabelle sortieren.


Die erste Spalte aus Abbildung 4 lässt (zwar nicht vollständig, aber in Ausschnitten) erkennen, dass die Reihen der Tabelle in aufsteigend sortierter Form vorliegen.

Schritt 4: Fallunterscheidungen in SQL

Die Anzahl der erzielten und erhaltenen Tore ist natürlich zu wenig, um daraus eine Tabelle generieren zu können. Wir erweitern die Abfrage daher um neue, zusätzliche Spalten für die Tordifferenz und die erzielten Punkte eines absolvierten Spiels. Die Tordifferenz lässt sich recht einfach mit Hilfe des Subtraktionsoperators bei Verwendung eines Aliasnamens generieren. Etwas diffiziler sieht es bei der Berechnung der Punkte für ein Spiel aus. In einer höheren Programmiersprache wäre dies an Hand einfacher Kontrollstrukturen wie if und else ein einfaches Unterfangen. Bei der Datenabfragesprache SQL geht dies auch, wenn gleich mit anderen Schlüsselwörtern. Es gelangt ein CASEWHENELSEEND–Ausdruck zum Einsatz:

SELECT TEAM, GOALSSELF, GOALSOTHER, GOALSSELF - GOALSOTHER AS GOALSDIFF,
CASE
    WHEN GOALSSELF > GOALSOTHER THEN 3
    WHEN GOALSSELF = GOALSOTHER THEN 1
    ELSE 0
END AS POINTS
FROM (
    SELECT GAMES.TEAMHOME AS TEAM, GAMES.GOALSHOME AS GOALSSELF,
        GAMES.GOALSAWAY AS GOALSOTHER FROM GAMES
    UNION ALL
    SELECT GAMES.TEAMAWAY AS TEAM, GAMES.GOALSAWAY AS GOALSSELF,
        GAMES.GOALSHOME AS GOALSOTHER FROM GAMES
)
ORDER BY TEAM ASC
Fallunterscheidungen in SQL.

Abbildung 5. Fallunterscheidungen in SQL.


Neben den bisherigen Spalten TEAM, GOALSSELF und GOALSOTHER finden wir in Abbildung 5 zwei neue Spalten GOALSDIFF und POINTS vor.

Schritt 5: Aggregatsfunktionen

Nun geht es um das Aufsummieren einzelner Spalten. Jetzt kommen die Aggregatsfunktionen ins Spiel, die eine GROUP-Anweisung erfordern:

SELECT
    TEAM, COUNT(*) AS GAMES, SUM (GOALSSELF) AS GSELF,
    SUM (GOALSOTHER) AS GOTHER, SUM (GOALSSELF - GOALSOTHER) AS GDIFF,
SUM ( CASE
    WHEN GOALSSELF > GOALSOTHER THEN 3
    WHEN GOALSSELF = GOALSOTHER THEN 1
    ELSE 0
END ) AS POINTS, 
SUM ( CASE
    WHEN GOALSSELF > GOALSOTHER THEN 1
    ELSE 0
END ) AS WINS,
SUM ( CASE
     WHEN GOALSSELF = GOALSOTHER THEN 1
     ELSE 0
END ) AS DRAWS,
SUM ( CASE
    WHEN GOALSSELF < GOALSOTHER THEN 1
    ELSE 0
END ) AS LOSSES
FROM (
    SELECT
        GAMES.TEAMHOME AS TEAM, GAMES.GOALSHOME AS GOALSSELF,
        GAMES.GOALSAWAY AS GOALSOTHER FROM GAMES
    UNION ALL
    SELECT
        GAMES.TEAMAWAY AS TEAM, GAMES.GOALSAWAY AS GOALSSELF,
        GAMES.GOALSHOME AS GOALSOTHER FROM GAMES
) 
GROUP BY TEAM

Siehe dazu das Resultat in Abbildung 6:

Aggregatsfunktionen.

Abbildung 6. Aggregatsfunktionen.


In Abbildung 6 finden wir jetzt zum ersten Mal eine Ergebnistabelle mit 18 Zeilen vor. Dies kommt einer Bundesligatabelle mit 18 Mannschaften doch schon recht nahe. Allerdings besitzt die Reihenfolge der Zeilen noch keinen Zusammenhang zur Anzahl der Punkte einer Mannschaft, womit wir beim nächsten Schritt angekommen sind:

Schritt 6: Sortieren einer Tabelle

Um zu einer richtigen Bundesligatabelle zu gelangen, müssen die einzelnen Zeilen der Abfrage in einer bestimmten Reihenfolge vorliegen. Für das Sortieren der relevanten Spalten müssen wir die letzte SQL-Anweisung aus Schritt 5 um eine ORDER BY-Anweisung ergänzen:

SELECT
    TEAM, COUNT(*) AS GAMESPLAYED, SUM (GOALSSELF) AS GSELF,
    SUM (GOALSOTHER) AS GOTHER, SUM (GOALSSELF - GOALSOTHER) AS GDIFF,
SUM ( CASE
    WHEN GOALSSELF > GOALSOTHER THEN 3
    WHEN GOALSSELF = GOALSOTHER THEN 1
    ELSE 0
END ) AS POINTS, 
SUM ( CASE
    WHEN GOALSSELF > GOALSOTHER THEN 1
    ELSE 0
END ) AS WINS,
SUM ( CASE
    WHEN GOALSSELF = GOALSOTHER THEN 1
    ELSE 0
END ) AS DRAWS,
SUM ( CASE
    WHEN GOALSSELF < GOALSOTHER THEN 1
    ELSE 0
END ) AS LOSSES
FROM (
    SELECT
        GAMES.TEAMHOME AS TEAM, GAMES.GOALSHOME AS GOALSSELF,
        GAMES.GOALSAWAY AS GOALSOTHER FROM GAMES
    UNION ALL
    SELECT
        GAMES.TEAMAWAY AS TEAM, GAMES.GOALSAWAY AS GOALSSELF,
        GAMES.GOALSHOME AS GOALSOTHER FROM GAMES
) 
GROUP BY TEAM
ORDER BY POINTS DESC, GDIFF DESC, GSELF DESC

Sehen Sie jetzt das Resultat in Abbildung 7:

Sortieren einer Tabelle zum Zweiten.

Abbildung 7. Sortieren einer Tabelle zum Zweiten.


Bei genauem Hinsehen in Abbildung 7 kann man an Hand der IDs der Mannschaften bzw. ihrer erzielten Punkte erkennen, dass diese in der richtigen Reihenfolge ausgegeben wurden. Damit sind wir schon beim letzen Schritt angekommen:

Schritt 7: Verknüpfung zweier Tabellen

Nun sind wir fast schon am Ende angekommen. Wir ergänzen die SQL-Abfrage noch um eine JOIN-Anweisung, um an Stelle der Mannschafts-IDs deren Namen im Ergebnis der Abfrage zu erhalten:

SELECT
    TEAMS.NAME AS TEAMNAME, COUNT(*) AS GAMESPLAYED, SUM (GOALSSELF) AS GSELF,
    SUM (GOALSOTHER) AS GOTHER, SUM (GOALSSELF - GOALSOTHER) AS GDIFF,
SUM ( CASE
    WHEN GOALSSELF > GOALSOTHER THEN 3
    WHEN GOALSSELF = GOALSOTHER THEN 1
    ELSE 0
END ) AS POINTS, 
SUM ( CASE
    WHEN GOALSSELF > GOALSOTHER THEN 1
    ELSE 0
END ) AS WINS,
SUM ( CASE
    WHEN GOALSSELF = GOALSOTHER THEN 1
    ELSE 0
END ) AS DRAWS,
SUM ( CASE
    WHEN GOALSSELF < GOALSOTHER THEN 1
    ELSE 0
END ) AS LOSSES
FROM (
    SELECT
        GAMES.TEAMHOME AS TEAMID, GAMES.GOALSHOME AS GOALSSELF,
        GAMES.GOALSAWAY AS GOALSOTHER FROM GAMES
    UNION ALL
    SELECT
        GAMES.TEAMAWAY AS TEAMID, GAMES.GOALSAWAY AS GOALSSELF,
        GAMES.GOALSHOME AS GOALSOTHER FROM GAMES
) AS TABLEENTRIES 
JOIN TEAMS ON TABLEENTRIES.TEAMID = TEAMS.ID 
GROUP BY TEAMID
ORDER BY POINTS DESC, GDIFF DESC, GSELF DESC

Voilà: Hier ist sie, die gesuchte Tabelle eines Ligaspielbetriebs (Abbildung 8):

Verknüpfung zweier Tabellen.

Abbildung 8. Verknüpfung zweier Tabellen.


Nun verlassen wir die Niederungen der Beschreibungssprache SQL und kommen auf eine WPF-Anwendung zu sprechen, die mittels eines C#-Wrappers auf eine SQLite-Datenbank zugreift. Für das Einbinden des Wrappers in die Anwendung darf ich Sie bitten, auf die zahlreichen Beschreibungen im Internet zuzugreifen. Um die Klassen des so genannten System.Data.SQLite-Wrappers benutzen zu können, müssen Sie im Quellcode die using-Direktive

using System.Data.SQLite;

platzieren. Damit kann es dann auch schon losgehen. Für die Datei auf der Festplatte Ihres Rechners, in der die Datenbank abgelegt wird, müssen Sie einen Namen vergeben. Für mein Beispiel habe ich den Namen LeagueData.db gewählt:

String dataSource = "LeagueData.db";

Als nächstes ist eine Datenbank-Verbindung zu öffnen. Die Klasse SQLiteConnection übernimmt diese Aufgabe:

SQLiteConnection connection = new SQLiteConnection();
connection.ConnectionString = "Data Source=" + dataSource;
connection.Open();

Damit wäre die Verbindung zur Datenbank hergestellt. Es können nun nach Belieben Tabellen erstellt und Daten hinzugefügt werden. Für das Erstellen einer Tabelle benötigt man ein Objekt der Klasse SQLiteCommand. Die Eigenschaft CommandText dieses Objekts erwartet eine syntaktisch korrekte SQLite-CREATE-Anweisung zum Generieren einer Tabelle, zum Beispiel auf diese Weise:

SQLiteCommand command = new SQLiteCommand (connection);
command.CommandText =
    "CREATE TABLE IF NOT EXISTS TEAMS " +
    "(ID INTEGER PRIMARY KEY NOT NULL, NAME TEXT NOT NULL, CITY TEXT NOT NULL);";
command.ExecuteNonQuery();
command.Dispose();

Ein Einfügen von Daten in einer Tabelle erfolgt auf dieselbe Weise. Die CommandText-Eigenschaft des SQLiteCommand-Objekts ist mit einer entsprechenden INSERT-Anweisung zu versorgen und über einen ExecuteNonQuery-Methodenaufruf an das Datenbanksystem zu senden.

Geringfügig anders sieht diese Vorgehensweise beim Auslesen von Daten aus der Datenbank aus, also beim Absetzen einer SQL-SELECT-Anweisung. Zusätzlich zu einem SQLiteCommand-Objekt kommt jetzt noch ein SQLiteDataReader-Objekt ins Spiel. Dieses wird vom SQLite-Laufzeitsystem angelegt, wenn am SQLiteCommand-Objekt ein ExecuteReader-Methodenaufruf abgesetzt wird, um eine Liste von Datensätzen als Ergebnis einer SQL-SELECT-Abfrage zu verwalten:

SQLiteCommand command = new SQLiteCommand (connection);
command.CommandText = "SELECT * FROM TEAMS";
SQLiteDataReader reader = command.ExecuteReader();

while (reader.Read())
{
    long rowId = (long) reader["ID"];
    String name = (String) reader["NAME"];
    String city = (String) reader["CITY"];
    Console.WriteLine("{0,2}: {1} [{2}]", rowId, name, city);
}

// release all resources
reader.Close();
reader.Dispose();
command.Dispose();

Nicht zu vergessen ist, dass viele der SQLite-Laufzeitobjekte Ressourcen im unterlagerten Datenbank- als auch Betriebssystem belegen. Diese Speicherbereiche sind mittels geeigneter Close und Dispose-Methodenaufrufe wieder freizugeben:

connection.Close();  
connection.Dispose();

Nun sollten alle Grundlagen einer SQLite-Datenbankanwendung auf Basis von C# vertraut sein, um eine WPF-Anwendung zum Berechnen und Betrachten einer Ligatabelle erstellen zu können. Das Aussehen der WPF-Anwendung hatten wir in Abbildung 1 schon vorgestellt. Mit einer XAML-Datei (Listing 1) zur Beschreibung der Anwendungsoberfläche sowie den programmiersprachlichen Anweisungen für den Ablauf der Anwendung (Listing 2) kommen wir zum Abschluss dieser Fallstudie:

01: <Window x:Class="WpfLigaTabelle.MainWindow"
02:         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
03:         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
04:         Title="League Tournament Sample" Height="600" Width="600">
05:     
06:     <DockPanel LastChildFill="True">
07:         <Grid DockPanel.Dock="Top">
08:              <Grid.ColumnDefinitions>
09:                 <ColumnDefinition />
10:                 <ColumnDefinition />
11:             </Grid.ColumnDefinitions>
12: 
13:             <Grid.RowDefinitions>
14:                 <RowDefinition />
15:                 <RowDefinition />
16:                 <RowDefinition />
17:                 <RowDefinition />
18:                 <RowDefinition />
19:                 <RowDefinition />
20:                 <RowDefinition />
21:             </Grid.RowDefinitions>
22: 
23:             <Button
24:                 Name="ButtonConnect" Click="Button_Click"
25:                 Grid.Row="0" Grid.Column="0">Connect to SQLite server</Button>
26:             <Button
27:                 Name="ButtonDisconnect" Click="Button_Click"
28:                 Grid.Row="0" Grid.Column="1">Disconnect from SQLite server</Button>
29:             <Button
30:                 Name="ButtonDisplaySQLiteDriverInfo" Click="Button_Click"
31:                 Grid.Row="1" Grid.Column="0"
32:                 Grid.ColumnSpan="2">Display SQLite server driver info</Button>
33:             <Button
34:                 Name="ButtonCreateTableTeams" Click="Button_Click"
35:                 Grid.Row="2" Grid.Column="0">Create table TEAMS</Button>
36:             <Button
37:                 Name="ButtonDeleteTableTeams" Click="Button_Click"
38:                 Grid.Row="2" Grid.Column="1">Delete table TEAMS</Button>
39:             <Button
40:                 Name="ButtonFillTableTeams" Click="Button_Click"
41:                 Grid.Row="3" Grid.Column="0">Insert data into table TEAMS</Button>
42:             <Button
43:                 Name="ButtonQueryTableTeams" Click="Button_Click"
44:                 Grid.Row="3" Grid.Column="1">Query Data from table TEAMS</Button>
45:             <Button
46:                 Name="ButtonCreateTableGames" Click="Button_Click"
47:                 Grid.Row="4" Grid.Column="0">Create Table GAMES</Button>
48:             <Button
49:                 Name="ButtonDeleteTableGames" Click="Button_Click"
50:                 Grid.Row="4" Grid.Column="1">Delete Table GAMES</Button>
51:             <Button
52:                 Name="ButtonFillTableGames" Click="Button_Click"
53:                 Grid.Row="5" Grid.Column="0">Insert Data into table GAMES</Button>
54:             <Button
55:                 Name="ButtonQueryTableGames" Click="Button_Click"
56:                 Grid.Row="5" Grid.Column="1">Query data from table GAMES</Button>
57:             <Button
58:                 Name="ButtonCreateLeagueTable" Click="Button_Click"
59:                 Grid.Row="6" Grid.Column="0">Create League Table (Console)</Button>
60:             <Button
61:                 Name="ButtonFillDataGrid" Click="Button_Click"
62:                 Grid.Row="6" Grid.Column="1">Create League Table (DataGrid)</Button>
63:         </Grid>
64: 
65:         <DataGrid
66:             Name="DataGridLeagueTable" CanUserAddRows="False" CanUserDeleteRows="False"
67:             CanUserReorderColumns="False" CanUserResizeColumns="True"></DataGrid>
68:     </DockPanel>
69: </Window>

Beispiel 1. Klasse MainWindow: XAML-Anteil des Hauptfensters.


001: public partial class MainWindow : Window
002: {
003:     private String dataSource = "LeagueData.db";
004: 
005:     // schema of table "TEAMS"
006:     private const String KEY1_ROWID = "ID";
007:     private const String KEY1_NAME  = "NAME";
008:     private const String KEY1_CITY  = "CITY";
009:     
010:     private const String DATATABLE_TEAMS_CREATE =
011:         "CREATE TABLE IF NOT EXISTS TEAMS (" +
012:         KEY1_ROWID + " INTEGER PRIMARY KEY NOT NULL," +
013:         KEY1_NAME + " TEXT NOT NULL," +
014:         KEY1_CITY + " TEXT NOT NULL);"; 
015:     
016:     private const String DATATABLE_TEAMS_SELECT =
017:         "SELECT * FROM TEAMS";
018:     private const String DATATABLE_TEAMS_DELETE =
019:         "DROP TABLE IF EXISTS TEAMS";
020: 
021:     // schema of table "GAMES"
022:     private const String KEY2_ROWID      = "ID";
023:     private const String KEY2_MATCHDAY   = "MATCHDAY";
024:     private const String KEY2_TEAMHOME   = "TEAMHOME";
025:     private const String KEY2_TEAMAWAY   = "TEAMAWAY";
026:     private const String KEY2_GOALSHOME  = "GOALSHOME";
027:     private const String KEY2_GOALSAWAY  = "GOALSAWAY";
028:     
029:     private const String DATATABLE_GAMES_CREATE =
030:         "CREATE TABLE IF NOT EXISTS GAMES (" +
031:         KEY2_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
032:         KEY2_MATCHDAY  + " INTEGER NOT NULL," +
033:         KEY2_TEAMHOME  + " INTEGER NOT NULL," +
034:         KEY2_TEAMAWAY  + " INTEGER NOT NULL," +
035:         KEY2_GOALSHOME + " INTEGER NOT NULL," +
036:         KEY2_GOALSAWAY + " INTEGER NOT NULL);"; 
037:     
038:     private const String DATATABLE_GAMES_SELECT =
039:         "SELECT * FROM GAMES";
040:     private const String DATATABLE_GAMES_DELETE =
041:         "DROP TABLE IF EXISTS GAMES";
042: 
043:     private const String DATATABLE_CREATE_LEAGUE_TABLE =
044:         "SELECT " +
045:             "TEAMS.NAME AS TEAMNAME, " +
046:             "COUNT(*) AS GAMESPLAYED, " +
047:             "SUM ( CASE " +
048:                 "WHEN GOALSSELF > GOALSOTHER THEN 1 " +
049:                 "ELSE 0 " +
050:             "END ) AS WINS, " +
051:             "SUM ( CASE " +
052:                 "WHEN GOALSSELF = GOALSOTHER THEN 1 " +
053:                 "ELSE 0 " +
054:             "END ) AS DRAWS, " +
055:             "SUM ( CASE " +
056:                 "WHEN GOALSSELF < GOALSOTHER THEN 1 " +
057:                 "ELSE 0 " +
058:             "END ) AS LOSSES, " +
059:             "SUM (GOALSSELF) AS GSELF, " +
060:             "SUM (GOALSOTHER) AS GOTHER, SUM (GOALSSELF - GOALSOTHER) AS GDIFF, " +
061:             "SUM ( CASE " +
062:                 "WHEN GOALSSELF > GOALSOTHER THEN 3 " +
063:                 "WHEN GOALSSELF = GOALSOTHER THEN 1 " +
064:                 "ELSE 0 " +
065:             "END ) AS POINTS " +
066:         "FROM (" +
067:             "SELECT " +
068:                 "GAMES.TEAMHOME AS TEAMID, GAMES.GOALSHOME AS GOALSSELF, " +
069:                 "GAMES.GOALSAWAY AS GOALSOTHER FROM GAMES " +
070:             " UNION ALL " +
071:             "SELECT " +
072:                 "GAMES.TEAMAWAY AS TEAMID, GAMES.GOALSAWAY AS GOALSSELF, " +
073:                 "GAMES.GOALSHOME AS GOALSOTHER FROM GAMES " +
074:         ") AS TABLEENTRIES " +
075:         "JOIN TEAMS ON TABLEENTRIES.TEAMID = TEAMS.ID " +
076:         "GROUP BY TEAMID " +
077:         "ORDER BY POINTS DESC, GDIFF DESC, GSELF DESC";
078: 
079:     private SQLiteConnection connection;
080: 
081:     public MainWindow()
082:     {
083:         this.InitializeComponent();
084:         this.connection = null;
085:     }
086: 
087:     private void Button_Click (Object sender, RoutedEventArgs e)
088:     {
089:         if (sender == this.ButtonConnect)
090:         {
091:             if (this.connection != null)
092:                 return;
093: 
094:             Console.WriteLine("Connecting to SQLite data source");
095:             this.connection = new SQLiteConnection();
096:             this.connection.ConnectionString = "Data Source=" + dataSource;
097:             this.connection.Open();
098:             Console.WriteLine("Done.");
099:         }
100:         else if (sender == this.ButtonDisconnect)
101:         {
102:             if (this.connection == null)
103:                 return;
104: 
105:             Console.WriteLine("Disconnecting from SQLite data source"); 
106:             this.connection.Close();
107:             this.connection.Dispose();
108:             this.connection = null;
109:             Console.WriteLine("Done.");
110:         }
111:         else if (sender == this.ButtonDisplaySQLiteDriverInfo)
112:         {
113:             if (this.connection == null)
114:                 return;
115: 
116:             Console.WriteLine("SQLite driver infos:");
117:             Console.WriteLine("ProviderVersion:  {0}", SQLiteConnection.ProviderVersion);
118:             Console.WriteLine("ServerVersion:    {0}", this.connection.ServerVersion);
119:             Console.WriteLine("SQLiteVersion:    {0}", SQLiteConnection.SQLiteVersion);
120:             Console.WriteLine("ConnectionString: {0}", this.connection.ConnectionString);
121:             Console.WriteLine("Done.");
122:         }
123:         else if (sender == this.ButtonCreateTableTeams)
124:         {
125:             if (this.connection == null)
126:                 return;
127: 
128:             Console.WriteLine("Creating table TEAMS");
129:             SQLiteCommand command = new SQLiteCommand(this.connection);
130:             command.CommandText = DATATABLE_TEAMS_CREATE;
131:             command.ExecuteNonQuery();
132:             command.Dispose();
133:             Console.WriteLine("Done.");
134:         }
135:         else if (sender == this.ButtonDeleteTableTeams)
136:         {
137:             if (this.connection == null)
138:                 return;
139: 
140:             Console.WriteLine("Deleting table TEAMS");
141:             SQLiteCommand command = new SQLiteCommand(this.connection);
142:             command.CommandText = DATATABLE_TEAMS_DELETE;
143:             command.ExecuteNonQuery();
144:             command.Dispose();
145:             Console.WriteLine("Done.");
146:         }
147:         else if (sender == this.ButtonFillTableTeams)
148:         {
149:             if (this.connection == null)
150:                 return;
151: 
152:             Console.WriteLine("Inserting data into table TEAMS");
153:             this.FillTableTeams();
154:             Console.WriteLine("Done.");
155:         }
156:         else if (sender == this.ButtonQueryTableTeams)
157:         {
158:             if (this.connection == null)
159:                 return;
160: 
161:             Console.WriteLine("Query data from table TEAMS");
162:             this.QueryTableTeams();
163:             Console.WriteLine("Done.");
164:         }
165:         else if (sender == this.ButtonCreateTableGames)
166:         {
167:             if (this.connection == null)
168:                 return;
169: 
170:             Console.WriteLine("Creating table GAMES");
171:             SQLiteCommand command = new SQLiteCommand(this.connection);
172:             command.CommandText = DATATABLE_GAMES_CREATE;
173:             command.ExecuteNonQuery();
174:             command.Dispose();
175:             Console.WriteLine("Done.");
176:         }
177:         else if (sender == this.ButtonDeleteTableGames)
178:         {
179:             if (this.connection == null)
180:                 return;
181: 
182:             Console.WriteLine("Deleting table GAMES");
183:             SQLiteCommand command = new SQLiteCommand(this.connection);
184:             command.CommandText = DATATABLE_GAMES_DELETE;
185:             command.ExecuteNonQuery();
186:             command.Dispose();
187:             Console.WriteLine("Done.");
188:         }
189:         else if (sender == this.ButtonFillTableGames)
190:         {
191:             if (this.connection == null)
192:                 return;
193: 
194:             Console.WriteLine("Inserting data into table GAMES");
195:             this.FillTableGames();
196:             Console.WriteLine("Done.");
197:         }
198:         else if (sender == this.ButtonQueryTableGames)
199:         {
200:             if (this.connection == null)
201:                 return;
202: 
203:             Console.WriteLine("Query data from table GAMES");
204:             this.QueryTableGames();
205:             Console.WriteLine("Done.");
206:         }
207:         else if (sender == this.ButtonCreateLeagueTable)
208:         {
209:             if (this.connection == null)
210:                 return;
211: 
212:             Console.WriteLine("Create League Table (Console)");
213:             this.CreateLeagueTable();
214: 
215:             Console.WriteLine("Done.");
216:         }
217:         else if (sender == this.ButtonFillDataGrid)
218:         {
219:             if (this.connection == null)
220:                 return;
221: 
222:             Console.WriteLine("Create League Table (DataGrid)");
223:             this.FillDataGrid();
224:             Console.WriteLine("Done.");
225:         }
226:     }
227: 
228:     private void QueryTableTeams()
229:     {
230:         SQLiteCommand command = new SQLiteCommand(this.connection);
231:         command.CommandText = "SELECT * FROM TEAMS";
232:         SQLiteDataReader reader = command.ExecuteReader();
233: 
234:         while (reader.Read())
235:         {
236:             long rowId = (long)reader[KEY1_ROWID];
237:             String name = (String)reader[KEY1_NAME];
238:             String city = (String)reader[KEY1_CITY];
239: 
240:             Console.WriteLine("{0,2}: {1} [{2}]", rowId, name, city);
241:         }
242: 
243:         // release all resources
244:         reader.Close();
245:         reader.Dispose();
246:         command.Dispose();
247:     }
248: 
249:     private void QueryTableGames()
250:     {
251:         SQLiteCommand command = new SQLiteCommand(this.connection);
252:         command.CommandText = "SELECT * FROM GAMES";
253:         SQLiteDataReader reader = command.ExecuteReader();
254: 
255:         while (reader.Read())
256:         {
257:             long id = (long)reader[KEY2_ROWID];
258:             long matchday = (long)reader[KEY2_MATCHDAY];
259:             long teamhome = (long)reader[KEY2_TEAMHOME];
260:             long teamaway = (long)reader[KEY2_TEAMAWAY];
261:             long goalshome = (long)reader[KEY2_GOALSHOME];
262:             long goalsaway = (long)reader[KEY2_GOALSAWAY];
263: 
264:             Console.WriteLine("ID = {0}, Matchday = {1}", id, matchday);
265:             Console.WriteLine("Teamhome = {0}, Teamaway = {1}, Goalshome = {2}, " +
266:                 "Goalsaway = {3}", teamhome, teamaway, goalshome, goalsaway);
267:         }
268: 
269:         // release all resources
270:         reader.Close();
271:         reader.Dispose();
272:         command.Dispose();
273:     }
274: 
275:     private void CreateLeagueTable()
276:     {
277:         SQLiteCommand command = new SQLiteCommand(this.connection);
278:         command.CommandText = DATATABLE_CREATE_LEAGUE_TABLE;
279:         SQLiteDataReader reader = command.ExecuteReader();
280: 
281:         for (int n = 1; reader.Read(); n++)
282:         {
283:             String teamname = (String) reader["TEAMNAME"];
284:             long count = (long)reader["GAMESPLAYED"];
285:             long gself = (long)reader["GSELF"];
286:             long gother = (long)reader["GOTHER"];
287:             long gdiff = (long)reader["GDIFF"];
288:             long points = (long)reader["POINTS"];
289: 
290:             long wins = (long)reader["WINS"];
291:             long draws = (long)reader["DRAWS"];
292:             long losses = (long)reader["LOSSES"];
293: 
294:             Console.WriteLine("{0,2}: Games = {1}, Team = {2,2}, Goalsself = {3}, " +
295:                 "Goalsother = {4}, Goalsdiff = {5,2}, Points = {6}",
296:                 n, count.ToString(), teamname, gself, gother, gdiff, points);
297:         }
298: 
299:         // release all resources
300:         reader.Close();
301:         reader.Dispose();
302:         command.Dispose();
303:     }
304: 
305:     private void FillDataGrid()
306:     {
307:         SQLiteCommand command = new SQLiteCommand(this.connection);
308:         command.CommandText = DATATABLE_CREATE_LEAGUE_TABLE;
309: 
310:         SQLiteDataAdapter adapter = new SQLiteDataAdapter(command);
311:         DataTable leagueTable = new DataTable();
312:         adapter.Fill(leagueTable);
313: 
314:         // change column names for better readybility
315:         leagueTable.Columns["TEAMNAME"].ColumnName = "Mannschaft";
316:         leagueTable.Columns["GAMESPLAYED"].ColumnName = "Spiele";
317:         leagueTable.Columns["WINS"].ColumnName = "S";
318:         leagueTable.Columns["DRAWS"].ColumnName = "U";
319:         leagueTable.Columns["LOSSES"].ColumnName = "N";
320:         leagueTable.Columns["GSELF"].ColumnName = "To";
321:         leagueTable.Columns["GOTHER"].ColumnName = "re";
322:         leagueTable.Columns["GDIFF"].ColumnName = "Diff";
323:         leagueTable.Columns["POINTS"].ColumnName = "Punkte";
324: 
325:         this.DataGridLeagueTable.ItemsSource = leagueTable.DefaultView;
326:         adapter.Update(leagueTable);
327: 
328:         // release all resources
329:         adapter.Dispose();
330:         command.Dispose();
331:     }
332: 
333:     private void FillTableTeams()
334:     {
335:         SQLiteCommand command = new SQLiteCommand(this.connection);
336: 
337:         command.CommandText =
338:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
339:             "VALUES (0, 'Hertha BSC', 'Berlin');";
340:         command.ExecuteNonQuery();
341: 
342:         command.CommandText =
343:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
344:             "VALUES (1, 'Borussia Dortmund', 'Dortmund');";
345:         command.ExecuteNonQuery();
346: 
347:         command.CommandText =
348:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
349:             "VALUES (2, 'Bayer Leverkusen', 'Leverkusen');";
350:         command.ExecuteNonQuery();
351: 
352:         command.CommandText =
353:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
354:             "VALUES (3, 'FC Bayern München', 'München');";
355:         command.ExecuteNonQuery();
356: 
357:         command.CommandText =
358:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
359:             "VALUES (4, 'Hannover 96', 'Hannover');";
360:         command.ExecuteNonQuery();
361: 
362:         command.CommandText =
363:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
364:             "VALUES (5, '1. FSV Mainz', 'Mainz');";
365:         command.ExecuteNonQuery();
366: 
367:         command.CommandText =
368:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
369:             "VALUES (6, 'SV Werder Bremen', 'Bremen');";
370:         command.ExecuteNonQuery();
371: 
372:         command.CommandText =
373:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
374:             "VALUES (7, 'Hamburger SV', 'Hamburg');";
375:         command.ExecuteNonQuery();
376: 
377:         command.CommandText =
378:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
379:             "VALUES (8, 'FC Schalke 04', 'Gelsenkirchen');";
380:         command.ExecuteNonQuery();
381: 
382:         command.CommandText =
383:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
384:             "VALUES (9, '1. FC Nürnberg', 'Nürnberg');";
385:         command.ExecuteNonQuery();
386: 
387:         command.CommandText =
388:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
389:             "VALUES (10, '1899 Hoffenheim', 'Hoffenheim');";
390:         command.ExecuteNonQuery();
391: 
392:         command.CommandText =
393:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
394:             "VALUES (11, 'VfB Stuttgart', 'Stuttgart');";
395:         command.ExecuteNonQuery();
396: 
397:         command.CommandText =
398:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
399:             "VALUES (12, 'Eintracht Braunschweig', 'Braunschweig');";
400:         command.ExecuteNonQuery();
401: 
402:         command.CommandText =
403:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
404:             "VALUES (13, 'SC Freiburg', 'Freiburg');";
405:         command.ExecuteNonQuery();
406: 
407:         command.CommandText =
408:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
409:             "VALUES (14, 'Borussia Mönchengladbach', 'Mönchengladbach');";
410:         command.ExecuteNonQuery();
411: 
412:         command.CommandText =
413:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
414:             "VALUES (15, 'VfL Wolfsburg', 'Wolfsburg');";
415:         command.ExecuteNonQuery();
416: 
417:         command.CommandText =
418:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
419:             "VALUES (16, 'FC Augsburg', 'Augsburg');";
420:         command.ExecuteNonQuery();
421: 
422:         command.CommandText =
423:             "INSERT INTO TEAMS (ID, NAME,CITY) " +
424:             "VALUES (17, 'Eintracht Frankfurt', 'Frankfurt');";
425:         command.ExecuteNonQuery();
426: 
427:         command.Dispose();
428:     }
429: 
430:     private void FillTableGames()
431:     {
432:         SQLiteCommand command = new SQLiteCommand(this.connection);
433: 
434:         // 1. Matchday
435:         command.CommandText = "INSERT INTO GAMES " +
436:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
437:             " VALUES (1, 3, 14, 3, 1);";
438:         command.ExecuteNonQuery();
439: 
440:         command.CommandText = "INSERT INTO GAMES " +
441:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
442:             " VALUES (1, 10, 9, 2, 2);";
443:         command.ExecuteNonQuery();
444: 
445:         command.CommandText = "INSERT INTO GAMES " +
446:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
447:             " VALUES (1, 2, 13, 3, 1);";
448:         command.ExecuteNonQuery();
449: 
450:         command.CommandText = "INSERT INTO GAMES " +
451:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
452:             " VALUES (1, 4, 15, 2, 0);";
453:         command.ExecuteNonQuery();
454: 
455:         command.CommandText = "INSERT INTO GAMES " +
456:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
457:             " VALUES (1, 16, 1, 0, 4);";
458:         command.ExecuteNonQuery();
459: 
460:         command.CommandText = "INSERT INTO GAMES " +
461:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
462:             " VALUES (1, 0, 17, 6, 1);";
463:         command.ExecuteNonQuery();
464: 
465:         command.CommandText = "INSERT INTO GAMES " +
466:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
467:             " VALUES (1, 12, 6, 0, 1);";
468:         command.ExecuteNonQuery();
469: 
470:         command.CommandText = "INSERT INTO GAMES " +
471:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
472:             " VALUES (1, 5, 11, 3, 2);";
473:         command.ExecuteNonQuery();
474: 
475:         command.CommandText = "INSERT INTO GAMES " +
476:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
477:             " VALUES (1, 8, 7, 3, 3);";
478:         command.ExecuteNonQuery();
479: 
480:         // 2. matchday
481:         command.CommandText = "INSERT INTO GAMES " +
482:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
483:             " VALUES (2, 11, 2, 0, 1);";
484:         command.ExecuteNonQuery();
485: 
486:         command.CommandText = "INSERT INTO GAMES " +
487:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
488:             " VALUES (2, 15, 8, 4, 0);";
489:         command.ExecuteNonQuery();
490: 
491:         command.CommandText = "INSERT INTO GAMES " +
492:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
493:             " VALUES (2, 6, 16, 1, 0);";
494:         command.ExecuteNonQuery();
495: 
496:         command.CommandText = "INSERT INTO GAMES " +
497:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
498:             " VALUES (2, 13, 5, 1, 2);";
499:         command.ExecuteNonQuery();
500: 
501:         command.CommandText = "INSERT INTO GAMES " +
502:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
503:             " VALUES (2, 7, 10, 1, 5);";
504:         command.ExecuteNonQuery();
505: 
506:         command.CommandText = "INSERT INTO GAMES " +
507:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
508:             " VALUES (2, 17, 3, 0, 1);";
509:         command.ExecuteNonQuery();
510: 
511:         command.CommandText = "INSERT INTO GAMES " +
512:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
513:             " VALUES (2, 14, 4, 3, 0);";
514:         command.ExecuteNonQuery();
515: 
516:         command.CommandText = "INSERT INTO GAMES " +
517:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
518:             " VALUES (2, 9, 0, 2, 2);";
519:         command.ExecuteNonQuery();
520: 
521:         command.CommandText = "INSERT INTO GAMES " +
522:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
523:             " VALUES (2, 1, 12, 2, 1);";
524:         command.ExecuteNonQuery();
525: 
526:         // 3. matchday
527:         command.CommandText = "INSERT INTO GAMES " +
528:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
529:             " VALUES (3, 1, 6, 1, 0);";
530:         command.ExecuteNonQuery();
531: 
532:         command.CommandText = "INSERT INTO GAMES " +
533:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
534:             " VALUES (3, 3, 9, 2, 0);";
535:         command.ExecuteNonQuery();
536: 
537:         command.CommandText = "INSERT INTO GAMES " +
538:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
539:             " VALUES (3, 2, 14, 4, 2);";
540:         command.ExecuteNonQuery();
541: 
542:         command.CommandText = "INSERT INTO GAMES " +
543:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
544:             " VALUES (3, 4, 8, 2, 1);";
545:         command.ExecuteNonQuery();
546: 
547:         command.CommandText = "INSERT INTO GAMES " +
548:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
549:             " VALUES (3, 10, 13, 3, 3);";
550:         command.ExecuteNonQuery();
551: 
552:         command.CommandText = "INSERT INTO GAMES " +
553:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
554:             " VALUES (3, 5, 15, 2, 0);";
555:         command.ExecuteNonQuery();
556: 
557:         command.CommandText = "INSERT INTO GAMES " +
558:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
559:             " VALUES (3, 0, 7, 1, 0);";
560:         command.ExecuteNonQuery();
561: 
562:         command.CommandText = "INSERT INTO GAMES " +
563:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
564:             " VALUES (3, 12, 17, 0, 2);";
565:         command.ExecuteNonQuery();
566: 
567:         command.CommandText = "INSERT INTO GAMES " +
568:             " (MATCHDAY, TEAMHOME, TEAMAWAY, GOALSHOME, GOALSAWAY) " +
569:             " VALUES (3, 16, 11, 2, 1);";
570:         command.ExecuteNonQuery();
571: 
572:         command.Dispose();
573:     }
574: }

Beispiel 2. Klasse MainWindow: Codebehind-Anteil des Hauptfensters.


Wenn man so möchte, kann man den Ablauf der Anwendung aus Listing 1 und Listing 2 auch in einer Konsole mitverfolgen. Zu diesem Zweck sind an den zentralen Stellen der Anwendung Console.WriteLine-Aufrufe vorhanden, um sich stets vom korrekten Ablauf der Anwendung überzeugen zu können:

Connecting to SQLite data source
Done.
SQLite driver infos:
ProviderVersion:  1.0.93.0
ServerVersion:    3.8.5
SQLiteVersion:    3.8.5
ConnectionString: Data Source=LeagueData.db
Done.
...
Disconnecting from SQLite data source
Done.