+ Antworten
Ergebnis 1 bis 14 von 14

C#: SqlCommand für Abfrage mit datetime und convert funktioniert nicht

Diskussion über C#: SqlCommand für Abfrage mit datetime und convert funktioniert nicht in .NET der Kategorie Programmierung; Hallo! Es geht um folgende Zeile in meinem Projekt: Code: cmd.CommandText = "SELECT * FROM Calibration WHERE CONVERT(char(8), end_time, 112) ...

  1. #1
    Reg.-Benutzer
    Reg.-Datum
    08.01.2009
    Beiträge
    21

    Standard C#: SqlCommand für Abfrage mit datetime und convert funktioniert nicht

    Hallo!

    Es geht um folgende Zeile in meinem Projekt:
    Code:
    cmd.CommandText = "SELECT * FROM Calibration WHERE CONVERT(char(8), end_time, 112) BETWEEN '" + dt1.ToString("yyyyMMdd") + "' AND '" + dt2.ToString("yyyyMMdd") + "' ";
    Zum Datenbankinhalt:
    end_time ist vom Typ datetime.
    Inhalte liegen in folgendem Format vor: "02.01.2011 23:59:59" und werden anhand von "CONVERT" und ".ToString" in das Format 20110102 gebracht.

    "cmd" ist vom Typ SqlCommand (using System.Data.SqlClient).
    dt1 sowie dt2 sind dateTimePicker Objekte die im Ereignis mit dem Wert gefüllt werden:

    Code:
    private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
    {
         dt1 = dateTimePicker1.Value;
    }
    Problem: Die Suche nach einem einzelnen Datum funktioniert einwandfrei. Ich verwende hierzu nicht BETWEEN sondern LIKE nur für dt1:
    Code:
    ...WHERE CONVERT(char(8), end_time, 112) LIKE '%" + dt1.ToString("yyyyMMdd") +"%' ";
    Wenn ich nun mit der ersten Anweisung über BETWEEN nach einem Datumsbereich suche, zeigt er mir keine Ergebnisse an, auch mit groß gewähltem Bereich über die Kalender.

    Gibt es ein Problem mit der Konvertierung?

    Danke!
    Grüße,
    Faby
    Geändert von Faby (26.01.2012 um 17:07 Uhr)

  2. #2
    Reg.-Benutzer
    Reg.-Datum
    12.05.2007
    Ort
    Dortmund
    Beiträge
    152

    Standard

    Ich würde eher mit Parametern arbeiten. SqlParameterCollection.AddWithValue bietet dir eine Übersicht. Hier mal ein Beispiel unter der Verwendung der Adventureworks-Datenbank:

    Code:
    SqlCommand cmd = new SqlCommand("select * from [AdventureWorks].[HumanResources].[Employee] WHERE HireDate BETWEEN @lowest AND @highest",conn);
    
    cmd.Parameters.AddWithValue("lowest", new DateTime(2000, 1, 1));
    cmd.Parameters.AddWithValue("highest", new DateTime(2002, 1, 1));
    Die String-Verkettung fällt weg, und die Lösung ist weniger fehleranfällig.

  3. #3
    Reg.-Benutzer
    Reg.-Datum
    01.04.2009
    Ort
    Heidenau / Sa.
    Beiträge
    71

    Standard

    Zitat Zitat von Faby Beitrag anzeigen
    Hallo!

    Zum Datenbankinhalt:
    end_time ist vom Typ datetime.
    Inhalte liegen in folgendem Format vor: "02.01.2011 23:59:59" und werden anhand von "CONVERT" und ".ToString" in das Format 20110102 gebracht.
    Ich gehe in der Annahme: MySQL?

    Aber datetime hat doch das Format 2011-01-02.
    Alternativ wenn Type datetime - auch noch mit Uhrzeit 2011-01-02 00:00:00

    Und @Gooose:
    Das ist zwar schön und gut, trägt aber nucht zur Lösung des Problems bei
    Geändert von raiserle (27.01.2012 um 01:41 Uhr) Grund: einfach noch mehr dazu....
    Wissen ist das einzige Gut, dass sich vermehrt, wenn man es teilt!

  4. #4
    Reg.-Benutzer Avatar von Gum'Mib'Aer
    Reg.-Datum
    02.02.2004
    Ort
    Saarland
    Beiträge
    11

    Standard

    Zitat Zitat von raiserle Beitrag anzeigen
    Ich gehe in der Annahme: MySQL?

    Aber datetime hat doch das Format 2011-01-02.
    Alternativ wenn Type datetime - auch noch mit Uhrzeit 2011-01-02 00:00:00[...]
    SqlCommand ist für MSSQL, MySQL wäre MySqlCommand.
    Daher trägt deine Antwort überhaupt nicht zur Lösung des Problems bei.
    Zitat Zitat von raiserle Beitrag anzeigen
    [...]
    Und @Gooose:
    Das ist zwar schön und gut, trägt aber nucht zur Lösung des Problems bei
    Die Lösung von Goose hingegen ist richtig und entspricht der empfohlenen Herangehensweise.

  5. #5
    Reg.-Benutzer
    Reg.-Datum
    12.05.2007
    Ort
    Dortmund
    Beiträge
    152

    Standard

    Zitat Zitat von raiserle Beitrag anzeigen
    Aber datetime hat doch das Format 2011-01-02.
    Das Format ist regionsabhängig. Bsp.:
    Code:
    CultureInfo ci = CultureInfo.GetCultureInfo("fr-FR");
    Console.WriteLine(DateTime.Now.ToString(ci));
    // Ausgabe: 27/01/2012 07:11:46
    Je nach dem an welchem Rechner gearbeitet wird, kann der String anders aussehen. Deswegen sollte man nach Möglichkeit mit DateTime Objekten arbeiten.

    Zitat Zitat von raiserle Beitrag anzeigen
    Alternativ wenn Type datetime - auch noch mit Uhrzeit 2011-01-02 00:00:00
    Da die Spalte in der DB auch vom Typ DateTime ist, sollte ein Mapping kein problem sein.

    Zitat Zitat von raiserle Beitrag anzeigen
    Und @Gooose:
    Das ist zwar schön und gut, trägt aber nucht zur Lösung des Problems bei
    Die Vergleiche in der Query sind alphanumerisch. Dies kann dazu führen, das falsche oder keine Ergebnisse zurückgegeben werden.

    Wenn man keinen Einfluss mehr auf die Eingabeparameter DT1 und DT2 hätte, kann folgendes funktionieren.
    Code:
    SELECT * FROM [AdventureWorks].[HumanResources].[Employee]
    WHERE HireDate BETWEEN CAST('2000-01-01' AS DATETIME) 
    AND CAST('2002-01-01' AS DATETIME)
    Hierbei müsste man sich aber wiederum auf die Ländereinstellungen des DBMS verlassen. Bei dieser Darstellung sind im angloamerikanischen Raum gerne mal Tag und Monat vertauscht. Das sind später Fehler, die schwer zu finden sind.

    Die Verwendung von DateTime Objekten nimmt dir diese Arbeit ab.

    Bei floating-points ist das Problem übrigens ähnlich, wenn man mit Strings arbeitet. Auch die String Repräsentation von Zahlen sind länderabhängig. (Dezimal- / Tausendertrenner)

  6. #6
    Reg.-Benutzer
    Reg.-Datum
    12.05.2007
    Ort
    Dortmund
    Beiträge
    152

    Standard

    Hier mal ein Thread wo es um ein ähnliches Thema geht:
    MSSQL / SqlCE DateTime Where Global halten

  7. #7
    Reg.-Benutzer
    Reg.-Datum
    08.01.2009
    Beiträge
    21

    Standard

    Danke für die Antworten! Zunächst die Frage: Was versteht man unter "Mapping"? Etwa das Suchen/Selektieren?

    Ich habe mit Parametern noch nie gearbeitet und sollte dazu auch sagen, dass ich aus der C++ Welt komme und mich erst seit kurzem mit C# beschäftige.

    Würde das so funktionieren? (Ich habe am Wochenende keinen Zugriff auf das Projekt)

    Code:
    cmd.CommandText = "SELECT * FROM Calibration WHERE CONVERT(char(8), end_time, 112) BETWEEN  @lowest AND @highest";
    Code:
    cmd.Parameters.AddWithValue("lowest", dt1.ToString("yyyyMMdd"));
    cmd.Parameters.AddWithValue("highest", dt2.ToString("yyyyMMdd"));
    Grüße,
    Faby

  8. #8
    Reg.-Benutzer
    Reg.-Datum
    12.05.2007
    Ort
    Dortmund
    Beiträge
    152

    Standard

    Zitat Zitat von Faby Beitrag anzeigen
    Was versteht man unter "Mapping"? Etwa das Suchen/Selektieren?
    Hierbei ist das Datentyp-Mapping zwischen .NET und SQL-Server gemeint. Hier mal eine Übersicht: Mapping CLR Parameter Data

    Zitat Zitat von Faby Beitrag anzeigen
    Ich habe mit Parametern noch nie gearbeitet ...
    Schau dir mal oben den Link an. Da ist es gut erklärt. Gerade am Anfang ist die MSDN ein guter Freund. Innerhalb des Visual Studios kommst du meistens direkt auf die passenden MSDN Seiten, wo du weitere Erklärungen zu .Net Klassen, - Methoden und - Properties findest.

    Zitat Zitat von Faby Beitrag anzeigen
    Ich habe am Wochenende keinen Zugriff auf das Projekt
    Die MS SQL Server Express Version kannst du dir kostenlos runterladen. Die Beispiel Datenbank Adventure Works findest du unter Codeplex. So kannst du dich projektunabhängig mit dem Thema beschäftigen.

    Probiere einfach mal ein wenig was aus. Dann bekommst du ein Gefühl für die Technik und merkst schneller was zielführend ist und was nicht.

    Wenn dt1 und dt2 vom Typ System.DateTime sind, kann die Abfrage so aussehen:

    Code:
    cmd.CommandText = "SELECT * FROM Calibration WHERE end_time BETWEEN  @lowest AND @highest";
    cmd.Parameters.AddWithValue("lowest", dt1);
    cmd.Parameters.AddWithValue("highest", dt2);
    Das Ziel des Ganzen ist es ja, auf die Datentyp Umwandlung nach Möglichkeit zu verzichten.

    Nimm dir die Zeit, und versuche nachzuvollziehen, was dort passiert. Das hilft dir, wenn du zukünftig auf ein ähnliches Problem triffst.

  9. #9
    Reg.-Benutzer
    Reg.-Datum
    08.01.2009
    Beiträge
    21

    Standard

    Zitat Zitat von Gooose Beitrag anzeigen
    Nimm dir die Zeit, und versuche nachzuvollziehen, was dort passiert. Das hilft dir, wenn du zukünftig auf ein ähnliches Problem triffst.
    Danke! Ich besorge mir gerade die benötigten Dateien.

    Mir stellen sich einige Fragen bezüglich SqlParameterCollection.AddWithValue:

    Code:
    command.Parameters.Add("@ID", SqlDbType.Int);
    Ich füge command dem Parameter "@ID" hinzu der vom Typ SqlDbType.Int ist zu?

    Code:
    command.Parameters["@ID"].Value = customerID;
    "@ID" wird eine Variable hinzugefügt, die vom Typ SqlDbType ist?
    D.h. customerID=5 ist äquivalent zu command.Parameters["@ID"].Value=5?

    Code:
    command.Parameters.AddWithValue("@demographics", demoXml);
    Wie oben mit customerID nur mit einer einzeiligen Anweisung?
    Geht man in diesem Beispiel davon aus, dass der Inhalt einer XML-Datei in "demoXml"
    vorher eingelesen wurde?


    Zitat Zitat von Gooose Beitrag anzeigen
    Das Ziel des Ganzen ist es ja, auf die Datentyp Umwandlung nach Möglichkeit zu verzichten.
    Stimmt. Wird für dt1 bspw. bei Auswahl des Datums 29.01.2012 eine Uhrzeit von 00:00:000 gespeichert, damit "lowest" auch wirklich die geringste anzunehmende Uhrzeit ist, um einen Vergleich mit BETWEEN zu ermöglichen?
    Somit ist sowohl der DateTimePicker als auch die SQL-Anweisung kompatibel zueinander, da beide vom selben Typ sind? Was passiert, wenn der DateTimePicker von einem anderen System mit unterschiedlicher Spracheinstellung zu dem System übermittelt, das den Befehl an die Datenbank ausführt? Werden beide in eine Art Standardformat gebracht, um Kompatibilität zu erreichen?

    Vielen Dank schon mal!

  10. #10
    Reg.-Benutzer
    Reg.-Datum
    12.05.2007
    Ort
    Dortmund
    Beiträge
    152

    Standard

    Zitat Zitat von Faby Beitrag anzeigen
    Code:
    command.Parameters.Add("@ID", SqlDbType.Int);
    Ich füge command dem Parameter "@ID" hinzu der vom Typ SqlDbType.Int ist zu?

    Code:
    command.Parameters["@ID"].Value = customerID;
    "@ID" wird eine Variable hinzugefügt, die vom Typ SqlDbType ist?
    D.h. customerID=5 ist äquivalent zu command.Parameters["@ID"].Value=5?
    Hier wird beschrieben wie der Parameter an den Sql-Server übergeben wird. Einfacher währe es hier zu sagen:

    Code:
    command.Parameters.AddWithValue("@ID", customerID);
    Das währe das gleiche Verhalten.

    Zitat Zitat von Faby Beitrag anzeigen
    Code:
    command.Parameters.AddWithValue("@demographics", demoXml);
    Wie oben mit customerID nur mit einer einzeiligen Anweisung?
    Geht man in diesem Beispiel davon aus, dass der Inhalt einer XML-Datei in "demoXml"
    vorher eingelesen wurde?
    Davon wird hier ausgegangen.

    Zitat Zitat von Faby Beitrag anzeigen
    Wird für dt1 bspw. bei Auswahl des Datums 29.01.2012 eine Uhrzeit von 00:00:000 gespeichert, damit "lowest" auch wirklich die geringste anzunehmende Uhrzeit ist, um einen Vergleich mit BETWEEN zu ermöglichen?
    In meinem Beispiel erzeuge ich ja ein DateTime Objekt ohne Zeitangabe. die Zeit wird hier mit Nullen belegt.

    Du kannst dir das beispielsweise im Command Window des Visual Studios anschauen:
    Code:
    >? new DateTime(2012,1,1).ToString()
    "01.01.2012 00:00:00"
    Weiteres kannst du unter DateTime in der MSDN nachlesen.

    Zitat Zitat von Faby Beitrag anzeigen
    Was passiert, wenn der DateTimePicker von einem anderen System mit unterschiedlicher Spracheinstellung zu dem System übermittelt, das den Befehl an die Datenbank ausführt? Werden beide in eine Art Standardformat gebracht, um Kompatibilität zu erreichen?
    Das müsste ich auch ausprobieren Ich denke aber, das mögliche auftretende Probleme durch das Verwenden von Parametern minimiert werden.

    Zitat Zitat von Faby Beitrag anzeigen
    Somit ist sowohl der DateTimePicker als auch die SQL-Anweisung kompatibel zueinander, da beide vom selben Typ sind?
    Kompatibel ist vielleicht ein wenig ungenau. Wir haben hier zwei Welten. Zum einen haben wir den SQL-Server, zum anderen die .NET Umgebung.

    Im Endeffekt hilft dir die SqlCommand Klasse SQL Statements an den Sql Server zu schicken.

    Aus dem Command

    Code:
    SqlCommand cmd = new SqlCommand("select * from [adventureworks].[humanresources].[employee] where hiredate between @lowest and @highest", conn);
    cmd.Parameters.AddWithValue("lowest", new DateTime(2000, 1, 1));
    cmd.Parameters.AddWithValue("highest", new DateTime(2002, 1, 1));
    kommt folgendes am SQL-Server an:

    Code:
    exec sp_executesql N'select * from [adventureworks].[humanresources].[employee] where hiredate between @lowest and @highest',N'@lowest datetime,@highest datetime',@lowest='2000-01-01 00:00:00',@highest='2002-01-01 00:00:00'
    Mit Hilfe von sp_executesql können SQL-Statements mit Parametern aufgerufen werden. Genau dabei hilft dir die SqlCommand Klasse.

    Am Rande:
    Was würdest du bei einem Insert / Update Statement machen? Wie würde wohl das SQL ohne die Verwendung von Parametern aussehen, wenn die Tabelle 10 oder mehr Spalten hat?

    Mein Tipp:
    Wenn ich mich in neue Themengebiete einarbeite, versuche ich die Komplexität so gering wie möglich zu halten.

    In diesem Fall, baue dir erst mal eine einfache Konsolen-Anwendung, die nichts weiter macht als dieses Statement abzusetzen. Wenn Fehler auftreten, kann man diese leichter lokalisieren.

  11. #11
    Reg.-Benutzer
    Reg.-Datum
    08.01.2009
    Beiträge
    21

    Standard

    Danke Goose.
    Das Insert / Update Statement kommt in naher Zukunft. Spätestens wenn ich mich für mein Abschlussprojekt damit beschäftigen muss Gerade beschäftige ich mich mit den zurückgegebenen Ergebnissen des SQL Statements. Ist es möglich ein SqlDataReader Objekt aus einer Methode zurückzugeben und ihn dann mit Read() weiterzuverwenden? Mein Problem: Da ich den Reader mit Close() schließen sollte, ihn danach aber mit return zurückgebe, kann ich kein Read() mehr darauf anwenden, was ja ziemlich verständlich ist. Wie jedoch gebe ich die Ergebnisse zurück, um sie danach weiterzuverwenden? Verwendet man da noch SqlDataReader?

  12. #12
    Reg.-Benutzer
    Reg.-Datum
    12.05.2007
    Ort
    Dortmund
    Beiträge
    152

    Standard

    Nehmen wir doch mal das obere Beispiel mit der Adventureworks DB:

    Mal angenommen eine Klasse für Employee würde so aussehen:

    Code:
    public class Employee
    {
        public int EmployeeID { get; set; }
        public string LoginID { get; set; }
        public DateTime? BirthDate { get; set; }
    }
    Wenn man jetzt eine Liste von Employee aus der Datenbank haben wollte, könnte die Abfrage so ausehen:

    Code:
    SqlCommand cmd = new SqlCommand("select * from [adventureworks].[humanresources].[employee] where hiredate between @lowest and @highest", conn);
    cmd.Parameters.AddWithValue("lowest", new DateTime(2000, 1, 1));
    cmd.Parameters.AddWithValue("highest", new DateTime(2002, 1, 1));
    
    SqlDataReader reader = cmd.ExecuteReader();
    List<Employee> result = new List<Employee>();
    while (reader.Read())
    {
        Employee currentEmployee = new Employee();
        currentEmployee.LoginID = (string)reader["LoginID"];
        currentEmployee.EmployeeID = (int)reader["EmployeeID"];
        currentEmployee.BirthDate = (DateTime?)reader["BirthDate"];
        result.Add(currentEmployee);
    }
    
    reader.Close();
    conn.Close();
    Jetzt könnte man die Liste zurückgeben und damit weiterarbeiten. Dies ist auch ein Beispiel dafür, wie man die SQL-Datentypen wieder "zurückmappt".

    Kurze Anmerkung zu dem "DateTime?":

    Beim SQL-Server lassen sich Datumsspalten nullen, was unter .NET nicht geht. Schau dir hierzu mal Nullable Types (C# Programming Guide) an. Wenn du unter .NET mit Datenbanken arbeitest, solltest du dich mit den Datentypen genau auseinandersetzen. Das erspart dir später viel Arbeit

    Schaue dir auch die beiden close Methoden an:
    SqlConnection.Close Method
    SqlDataReader.Close Method

    Das Freigeben von Ressourcen ist gerade bei Datenbanken wichtig.

  13. #13
    Reg.-Benutzer
    Reg.-Datum
    08.01.2009
    Beiträge
    21

    Standard

    Erneut Danke. Jetzt wird das ganze etwas klarer. Die Art und Weise wie in C# Speicherplatz allokiert wird ist neu für mich. Eine List habe ich zuvor noch nie verwendet.

    Grüße,
    Faby

  14. #14
    Reg.-Benutzer
    Reg.-Datum
    12.05.2007
    Ort
    Dortmund
    Beiträge
    152

    Standard

    Sicherlich wird auch speicher allokiert, doch ich meinte hier Resourcen im allgemeinen, sprich z.b. Anzahl von offenen Verbindungen zu einer Datenbank. Listen sind grundlegende Datenstrukturen. Vielleicht solltest du dich mit den Grundlagen auch nochmal auseinandersetzen.

Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)

     

Ähnliche Themen

  1. SqlCommand über verschiedene Server
    Von rikkert im Forum .NET
    Antworten: 3
    Letzter Beitrag: 10.06.2011, 12:25
  2. Bash - Abfrage funktioniert nicht
    Von bigred2010 im Forum Linux + Unix
    Antworten: 2
    Letzter Beitrag: 09.07.2008, 09:18
  3. Checkbox Abfrage - Wie funktioniert das?
    Von Rain im Forum Skript- und Webserverprogrammierung
    Antworten: 2
    Letzter Beitrag: 11.10.2003, 19:19
  4. CONVERT int klappt nicht
    Von Wellenreiter im Forum Skript- und Webserverprogrammierung
    Antworten: 1
    Letzter Beitrag: 09.11.2002, 16:08
  5. Maus funktioniert / funktioniert nicht...
    Von DocMabuse im Forum Hardware
    Antworten: 5
    Letzter Beitrag: 21.06.2002, 19:00

Die häufigsten Suchbegriffe für diese Seite:

sqldbtype.datetime datetimepicker falsches format