Ich erstelle eine SQL- Abfrage in C #. Dies hängt von einigen Bedingungen ab, die als Variablen im Code gespeichert sind.
string Query="SELECT * FROM Table1 WHERE 1=1 ";
if (condition1)
Query += "AND Col1=0 ";
if (condition2)
Query += "AND Col2=1 ";
if (condition3)
Query += "AND Col3=2 ";
Es funktioniert, aber das Testen von 1 = 1 scheint nicht elegant zu sein. Wenn ich es nicht verwenden würde, müsste ich mich jedes Mal daran erinnern und prüfen, ob der Abfrage bereits das Schlüsselwort "where" hinzugefügt wurde oder nicht.
Gibt es eine schönere Lösung?
42 = 42
;-)Select 42
Anfragen, die wir erhielten. (nicht amüsant war der Versuch, die Quelle aufzuspüren)If I didn't use it, I would have to remember and check every time if "where" keyword was already added or not to the query
- Deshalb benutzt du1 = 1
. Das Datenbankmodul optimiert es trotzdem, so dass es zwar hässlich aussieht, aber bei weitem der einfachste Weg ist, das Problem zu lösen.Antworten:
Speichern Sie die Bedingungen in einer Liste:
quelle
ToArray()
ist bei .NET 4 nicht erforderlich, da es eine Überlastung gibt, die keine akzeptiertIEnumerable<string>
.Eine Lösung besteht darin, Abfragen einfach nicht manuell durch Anhängen von Zeichenfolgen zu schreiben. Sie können ein ORM wie Entity Framework verwenden und mit LINQ to Entities die Funktionen verwenden, die Ihnen die Sprache und das Framework bieten:
quelle
PrintResults(query)
Abfrage dann in Dapper als Abfrage verwendet wird !!Ein bisschen übertrieben in diesem einfachen Fall, aber ich habe in der Vergangenheit ähnlichen Code verwendet.
Erstellen Sie eine Funktion
Verwenden Sie es so
Auf diese Weise müssen Sie, wenn keine Bedingungen gefunden werden, nicht einmal eine where-Anweisung in die Abfrage laden und dem SQL-Server eine Mikrosekunde Zeit sparen, um die Junk-where-Klausel zu verarbeiten, wenn die SQL-Anweisung analysiert wird.
quelle
Es gibt eine andere Lösung, die vielleicht auch nicht elegant ist, aber funktioniert und das Problem löst:
Zum:
SELECT * FROM Table1
,SELECT * FROM Table1 WHERE cond1
AND condN
quelle
WHERE
wenn es keine Prädikate gibt; Das 1 = 1 existiert speziell, um dies zu vermeiden.String query = "SELECT * FROM Table1";
und wechselnstring jointer = " WHERE ";
?WHERE
sollen dieAND
s zwischen Bedingungen gestellt werden?string joiner
Leitung durch ersetzenstring joiner = " WHERE ";
und diejoiner = " AND ";
Leitung in Ruhe lassen.Mach einfach so etwas:
Es ist SQL Injection Safe und meiner Meinung nach ziemlich sauber. Das
Remove()
entfernt einfach das letzteAND
;Es funktioniert sowohl, wenn keine Bedingungen festgelegt wurden, wenn eine festgelegt wurde oder wenn mehrere festgelegt wurden.
quelle
conditions != null
ist immer sotrue
, wenn du es mit initialisierst""
(außer in C #"" == null
). Es sollte wahrscheinlich ein Scheck sein, wennconditions
nicht leer ist… ;-)Fügen Sie einfach zwei Zeilen hinten hinzu.
Z.B
wird zu werden
Während
wird zu werden
=====================================
Vielen Dank, dass Sie auf einen Fehler dieser Lösung hingewiesen haben:
"Dies könnte die Abfrage unterbrechen, wenn eine der Bedingungen aus irgendeinem Grund den Text" 1 = 1 AND "oder" WHERE 1 = 1 "enthält. Dies kann der Fall sein, wenn die Bedingung eine Unterabfrage enthält oder versucht, zu überprüfen, ob welche vorhanden sind Die Spalte enthält beispielsweise diesen Text. Vielleicht ist dies in Ihrem Fall kein Problem, aber Sie sollten es berücksichtigen ... "
Um dieses Problem zu beseitigen, müssen wir das "Haupt" WHERE 1 = 1 von denen der Unterabfrage unterscheiden, was einfach ist:
Machen Sie einfach das "main" WHERE zu etwas Besonderem: Ich würde ein "$" - Zeichen anhängen
Dann noch zwei Zeilen anhängen:
quelle
"1=1 AND "
oder enthält" WHERE 1=1 "
. Dies kann beispielsweise der Fall sein, wenn die Bedingung eine Unterabfrage enthält oder versucht zu überprüfen, ob eine Spalte diesen Text enthält. Vielleicht ist dies in Ihrem Fall kein Problem, aber Sie sollten es im Auge behalten ...Benutze das:
quelle
QuerySub
ist meiner Meinung nach nicht besser oder schlechter als das Verwenden deswhere 1=1
Hacks. Aber es ist ein nachdenklicher Beitrag.... FROM SOMETABLE WHERE
; dannTrimEnd
würde das das eigentlich reduzieren auf... FROM SOMETABL
. Wenn dies tatsächlich ein warStringBuilder
(was es sein sollte, wenn Sie über so viel String-Manipulation oder mehr haben), können Sie einfachQuery.Length -= "WHERE ".Length;
.Warum nicht einen vorhandenen Query Builder verwenden? So etwas wie Sql Kata .
Es unterstützt komplexe Where-Bedingungen, Joins und Unterabfragen.
Es funktioniert mit SQL Server, MySQL und PostgreSql.
quelle
Die schnellste wörtliche Lösung für das, was Sie sich vorstellen können, ist folgende:
Es scheint nicht elegant zu sein, worauf ich Sie auf die Empfehlung von CodeCaster zur Verwendung eines ORM verweisen würde. Aber wenn Sie darüber nachdenken, was dies hier tut, sind Sie wirklich nicht besorgt darüber, 4 Zeichen Speicher zu verschwenden, und es ist für einen Computer sehr schnell, einen Zeiger um 4 Stellen zu bewegen.
Wenn Sie die Zeit haben, den Umgang mit einem ORM zu lernen, könnte sich dies für Sie wirklich auszahlen. Wenn Sie jedoch versuchen, zu verhindern, dass diese zusätzliche Bedingung die SQL-Datenbank erreicht, wird dies für Sie erledigt.
quelle
Wenn dies SQL Server ist , können Sie diesen Code viel sauberer machen.
Dies setzt auch eine bekannte Anzahl von Parametern voraus, was eine schlechte Annahme sein kann, wenn ich über die Möglichkeiten nachdenke.
In C # würden Sie verwenden:
Und dann auf der SQL-Seite:
quelle
Abhängig von der Bedingung kann möglicherweise eine boolesche Logik in der Abfrage verwendet werden. Etwas wie das :
quelle
Ich mag die fließende Oberfläche von Stringbuilder, deshalb habe ich einige ExtensionMethods erstellt.
quelle
IMHO, ich denke, dass Ihr Ansatz falsch ist:
Das Abfragen der Datenbank durch Verketten von Zeichenfolgen ist NIE eine gute Idee (das Risiko einer SQL-Injection und des Codes kann leicht beschädigt werden, wenn Sie an anderer Stelle Änderungen vornehmen).
Sie können ein ORM verwenden (ich verwende NHibernate ) oder zumindest verwenden
SqlCommand.Parameters
Wenn Sie unbedingt die Verkettung von Zeichenfolgen verwenden möchten, würde ich a verwenden
StringBuilder
(dies ist das richtige Objekt für die Verkettung von Zeichenfolgen):Wie der letzte Gedanke ist,
Where 1=1
ist wirklich hässlich, aber SQL Server wird es trotzdem optimieren.quelle
SELECT * FROM Table1 WHERE AND Col1=0
scheint nicht richtig zu sein, worum es gehtWHERE 1=1
.Der Dapper SqlBuilder ist eine ziemlich gute Option. Es wird sogar in der Produktion von StackOverflow verwendet.
Lesen Sie Sams Blogeintrag darüber .
Soweit ich weiß, ist es nicht Teil eines Nuget-Pakets. Sie müssen also den Code kopieren, in Ihr Projekt einfügen oder die Dapper-Quelle herunterladen und das SqlBuilder-Projekt erstellen. In beiden Fällen müssen Sie auch auf Dapper für die
DynamicParameters
Klasse verweisen .quelle
Ich sehe, dass dies in Oracle ständig verwendet wird, während dynamisches SQL in gespeicherten Prozeduren erstellt wird . Ich verwende es auch bei Abfragen, während ich Datenprobleme untersuche, um den Wechsel zwischen verschiedenen Datenfiltern zu beschleunigen ... Kommentieren Sie einfach eine Bedingung aus oder fügen Sie sie einfach wieder hinzu.
Ich finde es ziemlich häufig und leicht zu verstehen, wenn jemand Ihren Code überprüft.
quelle
Realisierung mit Erweiterungsmethoden.
quelle
Mit der
string
Funktion können Sie dies auch folgendermaßen tun:Ich persönlich fühle mich leicht, die bedingten Elemente am Ende zu entfernen, da ihre Position leicht vorherzusagen ist.
quelle
Ich dachte an eine Lösung, die vielleicht etwas lesbarer ist:
Ich bin mir nur nicht sicher, ob der SQL-Interpreter auch die
Col1 = Col1
Bedingung optimiert (gedruckt, wenncondition1
falsch).quelle
Hier ist ein eleganterer Weg:
quelle
Wie bereits erwähnt, ist das Erstellen von SQL durch Verkettung niemals eine gute Idee . Nicht nur wegen der SQL-Injection. Meistens, weil es nur hässlich, schwer zu warten und völlig unnötig ist . Sie müssen Ihr Programm mit Trace oder Debug ausführen, um zu sehen, welches SQL es generiert. Wenn Sie QueryFirst verwenden (Haftungsausschluss: den ich geschrieben habe), wird die unglückliche Versuchung beseitigt, und Sie können direkt in SQL vorgehen.
Diese Seite bietet eine umfassende Beschreibung der TSQL-Optionen zum dynamischen Hinzufügen von Suchprädikaten. Die folgende Option ist praktisch für Situationen, in denen Sie die Auswahl der Kombinationen von Suchprädikaten Ihrem Benutzer überlassen möchten.
QueryFirst gibt Ihnen C # null bis db NULL, also rufen Sie einfach die Execute () -Methode mit Nullen auf, wenn dies angebracht ist, und alles funktioniert einfach. <opinion> Warum zögern C # -Entwickler so sehr, Dinge in SQL zu tun, selbst wenn es einfacher ist? Mind buddgles. </ Opinion>
quelle
Für längere Filterschritte ist StringBuilder der bessere Ansatz, wie viele sagen.
Auf Ihren Fall würde ich gehen mit:
quelle
Prägnant, elegant und süß, wie im Bild unten gezeigt.
quelle