Hallo!
Es geht um folgende Zeile in meinem Projekt:
Zum Datenbankinhalt:Code:cmd.CommandText = "SELECT * FROM Calibration WHERE CONVERT(char(8), end_time, 112) BETWEEN '" + dt1.ToString("yyyyMMdd") + "' AND '" + dt2.ToString("yyyyMMdd") + "' ";
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:
Problem: Die Suche nach einem einzelnen Datum funktioniert einwandfrei. Ich verwende hierzu nicht BETWEEN sondern LIKE nur für dt1:Code:private void dateTimePicker1_ValueChanged(object sender, EventArgs e) { dt1 = dateTimePicker1.Value; }
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.Code:...WHERE CONVERT(char(8), end_time, 112) LIKE '%" + dt1.ToString("yyyyMMdd") +"%' ";
Gibt es ein Problem mit der Konvertierung?
Danke!
Grüße,
Faby
+ 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) ...
- 26.01.2012 16:58 #1Reg.-Benutzer
- Reg.-Datum
- 08.01.2009
- Beiträge
- 21
C#: SqlCommand für Abfrage mit datetime und convert funktioniert nicht
Geändert von Faby (26.01.2012 um 17:07 Uhr)
- 26.01.2012 22:09 #2Reg.-Benutzer
- Reg.-Datum
- 12.05.2007
- Ort
- Dortmund
- Beiträge
- 152
Ich würde eher mit Parametern arbeiten. SqlParameterCollection.AddWithValue bietet dir eine Übersicht. Hier mal ein Beispiel unter der Verwendung der Adventureworks-Datenbank:
Die String-Verkettung fällt weg, und die Lösung ist weniger fehleranfällig.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));
- 27.01.2012 01:39 #3Reg.-Benutzer
- Reg.-Datum
- 01.04.2009
- Ort
- Heidenau / Sa.
- Beiträge
- 71
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!
- 27.01.2012 07:19 #4
SqlCommand ist für MSSQL, MySQL wäre MySqlCommand.
Daher trägt deine Antwort überhaupt nicht zur Lösung des Problems bei.
Die Lösung von Goose hingegen ist richtig und entspricht der empfohlenen Herangehensweise.
- 27.01.2012 07:45 #5Reg.-Benutzer
- Reg.-Datum
- 12.05.2007
- Ort
- Dortmund
- Beiträge
- 152
Das Format ist regionsabhängig. Bsp.:
Je nach dem an welchem Rechner gearbeitet wird, kann der String anders aussehen. Deswegen sollte man nach Möglichkeit mit DateTime Objekten arbeiten.Code:CultureInfo ci = CultureInfo.GetCultureInfo("fr-FR"); Console.WriteLine(DateTime.Now.ToString(ci)); // Ausgabe: 27/01/2012 07:11:46
Da die Spalte in der DB auch vom Typ DateTime ist, sollte ein Mapping kein problem sein.
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.
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.Code:SELECT * FROM [AdventureWorks].[HumanResources].[Employee] WHERE HireDate BETWEEN CAST('2000-01-01' AS DATETIME) AND CAST('2002-01-01' AS DATETIME)
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)
- 27.01.2012 09:14 #6Reg.-Benutzer
- Reg.-Datum
- 12.05.2007
- Ort
- Dortmund
- Beiträge
- 152
Hier mal ein Thread wo es um ein ähnliches Thema geht:
MSSQL / SqlCE DateTime Where Global halten
- 28.01.2012 20:10 #7Reg.-Benutzer
- Reg.-Datum
- 08.01.2009
- Beiträge
- 21
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";
Grüße,Code:cmd.Parameters.AddWithValue("lowest", dt1.ToString("yyyyMMdd")); cmd.Parameters.AddWithValue("highest", dt2.ToString("yyyyMMdd"));
Faby
- 28.01.2012 21:35 #8Reg.-Benutzer
- Reg.-Datum
- 12.05.2007
- Ort
- Dortmund
- Beiträge
- 152
Hierbei ist das Datentyp-Mapping zwischen .NET und SQL-Server gemeint. Hier mal eine Übersicht: Mapping CLR Parameter Data
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.
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:
Das Ziel des Ganzen ist es ja, auf die Datentyp Umwandlung nach Möglichkeit zu verzichten.Code:cmd.CommandText = "SELECT * FROM Calibration WHERE end_time BETWEEN @lowest AND @highest"; cmd.Parameters.AddWithValue("lowest", dt1); cmd.Parameters.AddWithValue("highest", dt2);
Nimm dir die Zeit, und versuche nachzuvollziehen, was dort passiert. Das hilft dir, wenn du zukünftig auf ein ähnliches Problem triffst.
- 29.01.2012 01:43 #9Reg.-Benutzer
- Reg.-Datum
- 08.01.2009
- Beiträge
- 21
Danke! Ich besorge mir gerade die benötigten Dateien.
Mir stellen sich einige Fragen bezüglich SqlParameterCollection.AddWithValue:
Ich füge command dem Parameter "@ID" hinzu der vom Typ SqlDbType.Int ist zu?Code:command.Parameters.Add("@ID", SqlDbType.Int);
"@ID" wird eine Variable hinzugefügt, die vom Typ SqlDbType ist?Code:command.Parameters["@ID"].Value = customerID;
D.h. customerID=5 ist äquivalent zu command.Parameters["@ID"].Value=5?
Wie oben mit customerID nur mit einer einzeiligen Anweisung?Code:command.Parameters.AddWithValue("@demographics", demoXml);
Geht man in diesem Beispiel davon aus, dass der Inhalt einer XML-Datei in "demoXml"
vorher eingelesen wurde?
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!
- 29.01.2012 11:58 #10Reg.-Benutzer
- Reg.-Datum
- 12.05.2007
- Ort
- Dortmund
- Beiträge
- 152
Hier wird beschrieben wie der Parameter an den Sql-Server übergeben wird. Einfacher währe es hier zu sagen:
Das währe das gleiche Verhalten.Code:command.Parameters.AddWithValue("@ID", customerID);
Davon wird hier ausgegangen.
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:
Weiteres kannst du unter DateTime in der MSDN nachlesen.Code:>? new DateTime(2012,1,1).ToString() "01.01.2012 00:00:00"
Das müsste ich auch ausprobieren
Ich denke aber, das mögliche auftretende Probleme durch das Verwenden von Parametern minimiert werden.
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
kommt folgendes am SQL-Server an: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));
Mit Hilfe von sp_executesql können SQL-Statements mit Parametern aufgerufen werden. Genau dabei hilft dir die SqlCommand Klasse.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'
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.
- 31.01.2012 16:42 #11Reg.-Benutzer
- Reg.-Datum
- 08.01.2009
- Beiträge
- 21
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?
- 31.01.2012 17:43 #12Reg.-Benutzer
- Reg.-Datum
- 12.05.2007
- Ort
- Dortmund
- Beiträge
- 152
Nehmen wir doch mal das obere Beispiel mit der Adventureworks DB:
Mal angenommen eine Klasse für Employee würde so aussehen:
Wenn man jetzt eine Liste von Employee aus der Datenbank haben wollte, könnte die Abfrage so ausehen:Code:public class Employee { public int EmployeeID { get; set; } public string LoginID { get; set; } public DateTime? BirthDate { get; set; } }
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".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();
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.
- 31.01.2012 20:25 #13Reg.-Benutzer
- Reg.-Datum
- 08.01.2009
- Beiträge
- 21
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
- 01.02.2012 09:49 #14Reg.-Benutzer
- Reg.-Datum
- 12.05.2007
- Ort
- Dortmund
- Beiträge
- 152
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
-
SqlCommand über verschiedene Server
Von rikkert im Forum .NETAntworten: 3Letzter Beitrag: 10.06.2011, 12:25 -
Bash - Abfrage funktioniert nicht
Von bigred2010 im Forum Linux + UnixAntworten: 2Letzter Beitrag: 09.07.2008, 09:18 -
Checkbox Abfrage - Wie funktioniert das?
Von Rain im Forum Skript- und WebserverprogrammierungAntworten: 2Letzter Beitrag: 11.10.2003, 19:19 -
CONVERT int klappt nicht
Von Wellenreiter im Forum Skript- und WebserverprogrammierungAntworten: 1Letzter Beitrag: 09.11.2002, 16:08 -
Maus funktioniert / funktioniert nicht...
Von DocMabuse im Forum HardwareAntworten: 5Letzter Beitrag: 21.06.2002, 19:00

LinkBack URL
About LinkBacks
Zitieren