Entwickler-Ecke

WinForms - Abfrage einer Access-Datenbank


okrim - Fr 16.05.14 17:21
Titel: Abfrage einer Access-Datenbank
Hallo an alle,

hätte da wieder eine Frage und zwar will ich auf Daten meiner Access-Datenbank zugreifen, was prinzipiell so auch funktioniert

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
            OleDbConnection cn1 = new OleDbConnection(dbconnect);
            cn1.Open();
            string sql_abfrage1 = "SELECT * FROM [gesammt_stunden_tag] WHERE monat = '" + "12" + "' AND jahr = '" + "2014" + "'";
            OleDbCommand cmd1 = new OleDbCommand(sql_abfrage1, cn1);
            OleDbDataReader dr1 = cmd1.ExecuteReader();
            while (dr1.Read())
            {
                double std_gesamt_tag_dez = (float)dr1["std_gesamt"];
                std_gesamt_dez = std_gesamt_dez + std_gesamt_tag_dez;
            }
            cn1.Close();

so bekomme ich alle Stunden von Monat 12 und dem Jahr 2014, wie gesagt so funktioniert es auch.

Nur habe ich jetzt eine andere Tabelle wo ich das Jahr alleine nicht gespeichert habe, sonder nur das Datum und das als Text (z.B.: 16.05.2014) müsste aber auch nach Monat und Jahr suchen.

Freue mich über eure Hilfe

Gruß Mirko


Ralf Jansen - Fr 16.05.14 19:31

Habe und nutze kein Access insofern Code nur nach Doku.

Du willst scheinbar summieren das kann SQL selbst auch das bescheidene Access Sql. Du musst da nicht selber über die ganzen Datensätze rotieren. Das wäre auch ab einem bestimmten Punkt langsam da viele Einzelwerte von der Datenbank zu dir transportiert werden müsste anstatt nur die Endsumme. Connection und Commands immer richtig und so früh wie möglich schließen. In deinem Code ist das nicht garantiert. Using Statements helfen da.

Und ein Hinweis aus der Reihe. Diese kleingeschriebenen per Underscores getrennten Variablennamen sehen nach 80er Jahren MicroController C Code aus. Da dreht sich einem C# Entwickler der Magen um ;)


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
double summe;
using (var con = new OleDbConnection(connectionstring))
{
    con.Open();                
    using(var cmd = con.CreateCommand())
    {
        cmd.CommandText = @"SELECT SUM(WertSpalte) FROM Tabelle WHERE YEAR(DatumSpalte) = ? AND MONTH(DatumSpalte) = ?";
        cmd.Parameters.AddWithValue("ersterParameter"2014);  // Name ist egal OleDB ist zu blöd für benannte Parameter und geht nur nach Position
        cmd.Parameters.AddWithValue("zweiterParameter"12);
        summe = Convert.ToDouble(cmd.ExecuteScalar());                   
    }                
}


Th69 - Sa 17.05.14 07:05

Hallo okrim,

und bei dem Datum als Text-Spalte könntest du den LIKE [http://www.w3schools.com/sql/sql_like.asp]-Operator benutzen (sofern das Datum einheitlich als 'dd.mm.yyyy' geschrieben wurde).


okrim - Fr 23.05.14 19:42

Hallo Ralf,
hallo Th69,

ich DANKE euch vielmals, das klappt ja wunderbar.

Habe es jetzt folgendermaßen gelöst:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
using (var con = new OleDbConnection(dbconnect))
{
    con.Open();
    using (var cmd = con.CreateCommand())
    {
        cmd.CommandText = @"SELECT SUM(std_gesamt) FROM gesammt_stunden_tag WHERE monat = '" + "12" + "' AND datum LIKE '%2014'";
        std_gesamt_u_jan = Convert.ToDouble(cmd.ExecuteScalar());
    }
}


@ Th69
du hast geschrieben das der LIKE-Operator nur geht wenn ich das Datum einheitlich geschrieben habe, aber wenn ich das richtig kapiert habe ist doch egal was oder wie es vor 2014 steht, oder sehe ich das falsch?

Nochmals vielen Dank
Gruß Mirko


Ralf Jansen - Fr 23.05.14 19:51

Zitat:
du hast geschrieben das der LIKE-Operator nur geht wenn ich das Datum einheitlich geschrieben habe, aber wenn ich das richtig kapiert habe ist doch egal was oder wie es vor 2014 steht, oder sehe ich das falsch?


Wenn du garantieren kannst das auch wenn das Datumsfeld Freitext ist das immer eine 4-stellige Jahreszahl am Ende steht nicht.


okrim - Fr 23.05.14 20:06

das bedeutet wenn ich das Jahr immer vierstellig und am Ende stehen habe, ist es egal was z.B. vor 2014 steht?


Th69 - Fr 23.05.14 20:16

Hallo okrim,

ich dachte, du hättest nur die Datumsspalte (und nicht noch den Monat extra).
Und dann hättest du ja beides abfragen müssen, z.B.

SQL-Anweisung
1:
LIKE '%12.2014'                    

und - wie Ralf schon schrieb - käme es dann drauf an, ob das Datumsformat wirklich immer so aussieht (nicht daß z.B. die amerikanische Schreibweise 'mm/dd/yyyy' dort auftaucht oder eben nur die zweistellige Jahreszahl). ;-)


okrim - Fr 23.05.14 20:25

Ah ok, dann habe ich es kapiert :D
Danke nochmal!

Eine Frage hätte ich jetzt aber doch noch,
wenn z.B. im Juni noch keine Stunden in meiner Datenbank sind würde ich gerne 0 Std. ausgeben, wie könnte ich dies am besten lösen oder abfragen?


Th69 - Fr 23.05.14 20:28

Kommt denn dann nicht automatisch 0 bei der Summe raus?


okrim - Fr 23.05.14 20:39

nein leider nicht!

habe folgenden Code:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
double std_gesamt_u_jun = 0;

// Lädt gesamt Stunden Juni
using (var con06 = new OleDbConnection(dbconnect))
{
    con06.Open();
    using (var cmd06 = con06.CreateCommand())
    {
        cmd06.CommandText = @"SELECT SUM(std_gesamt) FROM gesammt_stunden_tag WHERE monat = '" + "06" + "' AND datum LIKE '%" + numericUpDown_jahr_u.Value + "'";
        std_gesamt_u_jun = Convert.ToDouble(cmd06.ExecuteScalar());
    }
}


wenn ich das ganze im Debugg Modus starte, geht es nach diesen Zeilen nicht mehr weiter, es kommt aber auch kein Fehler, ich schreibe die Stunden in ein DataGridView das bleibt komplett leer, wenn ich den Juni ausklammer dann bekomme ich alle Einträge bis Mai.


Edit:
Ich könnte natürlich mit IF abfragen welcher Aktuelle Monat im Moment ist und lass dann die Datenbankabfrage für Juni erst zu, wenn Juni ist.
Aber da gibt es bestimmt noch elegantere Lösungen, oder?


Edit:
So würde es gehen:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
// Lädt gesamt Stunden Juni
if (Convert.ToDouble(datum) <= 06)
    std_gesamt_u_jun = 0;
else
{
    using (var con06 = new OleDbConnection(dbconnect))
    {
        con06.Open();
        using (var cmd06 = con06.CreateCommand())
        {
            cmd06.CommandText = @"SELECT SUM(std_gesamt) FROM gesammt_stunden_tag WHERE monat = '" + "06" + "' AND datum LIKE '%" + numericUpDown_jahr_u.Value + "'";
            std_gesamt_u_jun = Convert.ToDouble(cmd06.ExecuteScalar());
        }
    }
}


Ralf Jansen - Fr 23.05.14 21:06

Wenn es keine Daten gibt kommt da null (was als DBNULL Typ dann in .NET aufschlägt) zurück. Der Convert.ToDouble sollte dann eine Exception werfen. Ich vermute mal du hast dein Fehlerhandling vernachlässigt bzw. gleich weggelassen.

Um nicht null sondern 0, im Fall das keine Daten da sind, zurückzubekommen gibt es eventuell eine IsNull Methode.


C#-Quelltext
1:
2:
cmd06.CommandText = @"SELECT ISNULL(SUM(std_gesamt),0) FROM gesammt_stunden_tag WHERE monat = '" + "06" +
                     "' AND datum LIKE '%" + numericUpDown_jahr_u.Value + "'";


Moderiert von user profile iconTh69: Quote- durch C#-Tags ersetzt


okrim - Sa 24.05.14 06:32

Danke Ralf,

aber das funktioniert auch nicht ich lass es einfach mit meiner IF abfrage das funkzioniert.

Was mich jetzt noch interessieren würde ist, warum ich nur eine Open anweisung habe, brauch ich da nicht auch irgendwann wieder Close?


Th69 - Sa 24.05.14 07:55

Durch das using(...) wird automatisch bei Blockende Dispose() aufgerufen, welches dann intern wiederum Close() aufruft.