SQL Builder i C#
HalløjFra de gode gamle ASP dage har jeg et script der kunne generere en sql streng til brug for søgning boolske operatorer. Er der en der har et lignende script i C#?
Scriptet ser således ud:
'Definerer de to variabler, der benyttes af GetWord proceduren. Se den for
'yderligere informationer.
Dim CurWord, CurWordLen
'Sættes en konstant, som benyttes til at indsættes det rette wildcard i
'SQL udtrykket.
'Bruges VB, er wildcard'et "*"
'Bruges ASP, er wildcard'et "%"
Const ACCESS_WILDCARD = "%"
Function SQLClause(SearchString, TableList)
'Erklær en række variabler, der skal bruges i funktionen:
' bln: Hvis denne er True, indsættes der ikke nogen boolske udtryk i den endelige
' SQL-sætning. Dvs, at man ikke får en fejl, hvis der står "and or" i søge-
' udtrykket. Her ignoreres "or". Brugen af "not" har intet med dette at gøre.
' curOut / curOut2: Temporære variabler, der benyttes når man skal tilføje en
' streng til søgeudtrykket.
' l(): Et array, der indeholder en liste over tabeller.
Dim bln, curOut, curOut2
'Opsplit argumentet TableList til det dynamiske array l()
l = Split(TableList, ",")
'Der skal ikke være nogle boolske udtryk til at starte med (dvs. vi kan ikke starte
'med "and" eller "or". "Not" er naturligvis en undtagelse.
bln = True
'Evaluér SearchString således at der ikke opstår fejl. Læs funktionen for mere info
'om denne evaluering.
SearchString = SQLValSearchString(SearchString)
'Efterhånden som dele af søgeudtrykket evalueres, slettes det fra strengen. Når der
'ikke er mere af udtrykket (Len(SearchString)=0), stoppes løkken, og SQL betingelsen
'skulle være parat.
Do While Len(SearchString) > 0
'Hent det næste "ord" fra SearchString. Et ord kan også være (, ) eller en
'længere streng indgrænset af "".
'Eksempelvis bliver (hej and sa) or "med dig"
' - (
' - hej
' - and
' - sa
' - )
' - or
' - med dig
'GetWord er en procedure, som sætter det nye ord og længden af den del af
'SearchString, der bruges til at finde dette ord, i CurWord og CurWordLen.
GetWord SearchString
Select Case CurWord
'Hvis CurWord er ( eller ) skal parentesen sådan set bare tilføjes til
'SQL udtrykket. Med det forbehold at der skal være et "and" eller et "or"
'foran venstreparenteser. Dette gælder naturligvis ikke i starten, men
'værdien af bln tager højde for dette.
Case "("
If Not bln Then Out = Out & " AND "
Out = Out & "("
Case ")"
Out = Out & ")"
'Hvis der endnu ikke er tilføjet et "and" eller et "or" til SQL udtrykket
'siden sidste LIKE-sammenligning (indikeret ved værdien af bln), skal der
'tilføjes CurWord, hvis dette er "and" eller "or".
Case "and", "or"
If Not bln Then
Out = Out & " " & UCase(CurWord) & " "
'bln opdateres naturligvis nu da et "and" eller "or" er tilføjet
bln = True
End If
'Hvis CurWord er "not" er det anderledes. Der skal være et "or" eller et
'"and" foran "not" (igen indikeret ved bln).
Case "not"
If Not bln Then Out = Out & " AND "
Out = Out & "NOT "
'bln opdateres naturligvis nu da et "and" eller "or" er tilføjet
bln = True
'Og så dét, det i virkeligheden handler om
Case Else
'Hvis der endnu ikke er blevet tilføjet et "and" eller "or" siden sidste
'LIKE-sammenligning, gøres det nu.
If Not bln Then Out = Out & " AND "
'curOut sættes til LIKE-sammenligningen. $$$ er stedet, hvor navnet på
'databasen i posten skal tilføjes.
curOut = "($$$ LIKE '" & ACCESS_WILDCARD & CurWord & ACCESS_WILDCARD & "')"
'curOut2 sættes til en tom streng. curOut2 skal indeholde denne specifikke
'LIKE-sammenligning for alle posterne, der er angivet i parametret TableList.
curOut2 = ""
'En LIKE-sammenligning for hver post tilføjes til curOut2 og de sammenkædes
'med " OR ".
For i = LBound(l) To UBound(l)
curOut2 = curOut2 & Replace(curOut, "$$$", l(i))
If i <> UBound(l) Then curOut2 = curOut2 & " OR "
Next
'Endeligt sættes der parenteser omkring.
Out = Out & "(" & curOut2 & ")"
'Og bln sættes til False (dvs. der vil blive tilføjet enten et "and" eller
'en ) som det næste.
bln = False
End Select
'Det af strengen, der er blevet evalueret skæres væk.
For i = 1 To CurWordLen
SearchString = Cut(SearchString, 1)
Next
Loop
'Out indeholder nu det, der skal bruges, så der sættes () omkring udtrykkes,
'og funktionen returnerer.
SQLClause = "(" & Out & ")"
End Function
Function SQLValSearchString(SearchString)
'Undgå SQL problemer med en enkelt apostrof.
SearchString = Replace(SearchString, "'", "''")
'Konvertér tabs til mellemrum
SearchString = ReplaceEx(SearchString, vbTab, " ")
'/***
'Her følger der nogle omskrivninger af de boolske operatorer, som
'for så vidt er ligegyldige for denne fase, men det er meget sjovt
'at tillade brugen at bruge dem.
'Bemærk at ReplaceEx bruges, hvorved der tages højde for anførselstegn
'Der kan være ulemper ved brugen af nogle af disse.
'eksempelvis kan et ord med bindestreg blive omformuleret til noget
'med NOT. Vælg selv hvilke operatorer, du vil bruge.
'Har du flere ideer til operatorer: Send en mail, så andre kan få
'noget ud af din ide.
'Koverter enkeltstående && til AND
SearchString = ReplaceEx(SearchString, "&&", " and ")
'Koverter enkeltstående & til AND
SearchString = ReplaceEx(SearchString, "&", " and ")
'Koverter enkeltstående || til OR
SearchString = ReplaceEx(SearchString, "||", " or ")
'Koverter enkeltstående | til OR
SearchString = ReplaceEx(SearchString, "|", " or ")
'Koverter enkeltstående + til AND
SearchString = ReplaceEx(SearchString, "+", " and ")
'Koverter enkeltstående - til NOT
'SearchString = ReplaceEx(SearchString, "-", " not ")
'Koverter enkeltstående ! til NOT
SearchString = ReplaceEx(SearchString, "!", " not ")
'***/
'Sørg for at kunne nøjes med én sammenligning ligemeget
'hvordan brugeren har defineret søgningen. "AND", "and"
'og "aNd" skulle gerne være det samme.
SearchString = LCase(SearchString)
'Definer de variabler, der skal benyttes til at
'angive status i konverteringen.
Dim Pos
'Hvis der er et ulige antal "'er opstår der problemer.
'Dette omgås ved at fjerne det sidste ", der forekommer.
'Nogen andre løsningsforslag?
If Not IsEqual(AntalAfTegn(SearchString, """")) Then SearchString = Cut(SearchString, InStrRev(SearchString, """"))
'Søgestrengen trimmes. Der skal ...
'...aldrig være mere end ét mellemrum mellem to ord.
'...aldrig være mellemrum efter en VParentes.
'...aldrig være mellemrum før en HParentes.
'...aldrig være mellem i start eller slut
'Start + slut
SearchString = Trim(SearchString)
'Ikke to mellemrum efter hinanden
Do While InStrEx(SearchString, " ", 1) > 0
SearchString = ReplaceEx(SearchString, " ", " ")
Loop
'/***
'Bemærk at dobbeltmellemrum er fjernet; der kræves ingen løkke
'Ikke noget mellemrum efter VParentes
SearchString = ReplaceEx(SearchString, "( ", "(")
'Ikke noget mellemrum før HParentes
SearchString = ReplaceEx(SearchString, " )", ")")
'***/
'Mens der er højre-parenteser før venstreparenteser, skal
'disse højreparenteser fjernes. Ellers kan der senere opstå
'problemer. Der tages højde for anførselstegn, og der sørges
'nedenfor for at der er lige mange v- og h-parenteser.
Do While InStrEx(SearchString, ")", 1) < InStrEx(SearchString, "(", 1) And InStrEx(SearchString, ")", 1) <> 0
SearchString = Cut(SearchString, InStrEx(SearchString, ")", 1))
Loop
'Hvis der er flere )'er end ('er skal der tilføjes nogle ('er.
'Der skal være lige mange venstre- og højre parenteser, ellers
'opstår der problemer senere. Bemærk i øvrigt at AntalAfTegnEx
'tager højde for anførselstegn. Derfor tælles parenteser inden
'for sådanne ikke med i udregningen
Do While AntalAfTegnEx(SearchString, "(") < AntalAfTegnEx(SearchString, ")")
SearchString = "(" & SearchString
Loop
'Og så ellers omvendt...
Do While AntalAfTegnEx(SearchString, ")") < AntalAfTegnEx(SearchString, "(")
SearchString = SearchString & ")"
Loop
SQLValSearchString = SearchString
End Function
'Returnerer antal af et givent Tegn i Str.
Function AntalAfTegn(Str, Tegn)
For i = 1 To Len(Str)
If Mid(Str, i, 1) = Tegn Then AntalAfTegn = AntalAfTegn + 1
Next
End Function
'Returnerer antal af et givent Tegn i Str, der ikke er indgrænset af "".
Function AntalAfTegnEx(Str, Tegn)
Dim Anforsel
For i = 1 To Len(Str)
If Mid(Str, i, 1) = """" Then Anforsel = Not Anforsel
If Mid(Str, i, 1) = Tegn And Not Anforsel Then AntalAfTegnEx = AntalAfTegnEx + 1
Next
End Function
'Returnerer placeringen af String2 i String1, der ikke er indgræset af "". Starter ved placering StartWith
Function InStrEx(String1, String2, StartWith)
Dim l1, l2, i, Anforsel
l1 = Len(String1)
l2 = Len(String2)
If l2 = 0 Then
InStrEx = 0
Exit Function
Else
For i = StartWith To l1 - l2 + 1
If Mid(String1, i, 1) = """" Then Anforsel = Not Anforsel
If Mid(String1, i, l2) = String2 And Not Anforsel Then
InStrEx = i
Exit Function
End If
Next
End If
InStrEx = 0
End Function
'Returnerer en streng, hvor sFind er erstattet med sReplace i Str.
'Dog hvor sFind ikke er indgrænset af ""
Function ReplaceEx(Str, sFind, sReplace)
Dim Pos, Start
Pos = InStrEx(Str, sFind, 1)
Do While Pos > 0
For i = 1 To Len(sFind)
Str = Cut(Str, Pos)
Next
Str = Insert(Str, sReplace, Pos)
Pos = InStrEx(Str, sFind, Pos + Len(sReplace))
Loop
ReplaceEx = Str
End Function
'Returnerer en boolsk værdi, der indikerer om n er et lige tal.
Function IsEqual(n)
IsEqual = ((n / 2) = Int(n / 2))
End Function
'Returnerer er den streng, hvor karakteren på position Pos fra strengen Str er skåret væk.
Function Cut(Str, Pos)
Cut = Left(Str, Pos - 1) & Right(Str, Len(Str) - Pos)
End Function
'Indsætter strengen From i Into på position Pos. Returnerer denne streng.
Function Insert(Into, From, Pos)
Dim Before, After
If Pos < 1 Then Pos = 1
If Len(Into) = 0 Then
Insert = From
ElseIf Pos > Len(Into) Then
Insert = Into & From
Else
Before = Left(Into, Pos - 1)
After = Right(Into, (Len(Into) - Pos) + 1)
Insert = Before & From & After
End If
End Function
'Henter det første ord fra Str, og sætter denne værdi i CurWord. Et "ord" kan være
' (
' )
' et ord indgrænset af to mellemrum
' en streng indgrænset af to ""
'CurWordLen sættes til længden af det udtryk fra Str, der benyttes til at bestemme CurWord.
'Eksempelvis medtages "'er ikke i CurWord, mens de tæller med i CurWordLen.
Sub GetWord(Str)
Dim i, CurSubStr, Anforsel, Out
For i = 1 To Len(Str)
CurSubStr = Mid(Str, i, 1)
If CurSubStr = """" Then
Anforsel = Not Anforsel
Else
If (CurSubStr = " " Or CurSubStr = "(" Or CurSubStr = ")") And Not Anforsel Then
If Len(Out) > 0 Then
i = i - 1
Exit For
ElseIf CurSubStr = "(" Or CurSubStr = ")" Then
Out = CurSubStr
Exit For
End If
Else
Out = Out & CurSubStr
End If
End If
Next
CurWord = Out
CurWordLen = Min(i, Len(Str))
End Sub
'Returnerer den mindste værdi af m og n.
Function Min(m, n)
If m < n Then
Min = m
Else
Min = n
End If
End Function
