Tuesday, February 19, 2013

Use VB.NET to get the from part of SQL query

Hello, long time no post...

this is a function I've written to extract the from part of a SQL query. When you first get this assignment it sounds simple. But once you start thinking about it, it becomes more and more complex. How do you handle sub-queries in the select and where clause. How do you handle unions, ...

The function I've written works by calculating the nesting level of your query. This is done by adding 1 to a counter if you encounter a ( and subtracting 1 from the counter if you find a ). If you then find the word "from" and the nesting level = 0 you've got the from part. The next problem is what if the query contains an extra ( or )
This can happen for example with the following query: select replace(field,'(',' '),* from table
So this simple query would ruin my whole function :-)

I solved this by only increasing and decreasing the nesting level if there are no quotes open.

I've included two functions, one which can handles union and returns the from part of every separate query joined by a union. The first function can't cope with a union, but you can use this if you know there won't be a union. If anyone finds other queries which these functions can't handle, please let me know.


 Public Function GetFromPartOfAQuery(SourceQuery As String) As String  
       Dim nestLevel As Integer = 0  
       Dim blnQuoteOpen As Boolean = False  
       Dim strReturn As String = ""  
       Dim iIndex As Integer = 0  
       Dim strWord As String = ""  
         For Each c As Char In query  
           iIndex += 1  
           If c = "'"c And blnQuoteOpen = False Then  
             blnQuoteOpen = True  
           Else  
             If c = "'"c And blnQuoteOpen = True Then  
               blnQuoteOpen = False  
             End If  
           End If  
           If c = "(" AndAlso blnQuoteOpen = False Then  
             nestLevel += 1  
           End If  
           If c = ")" AndAlso blnQuoteOpen = False Then  
             nestLevel -= 1  
           End If  
           If c = " "c Then  
             strWord = ""  
           Else  
             strWord &= c  
           End If  
           If strWord.ToLower = "from" And nestLevel = 0 Then  
             strReturn = Mid(query, iIndex - 3, query.Length - (iIndex - 4))  
             Exit For  
           End If  
         Next  
       Return lstReturn  
     End Function  


 Public Function GetFromPartOfAQuery(SourceQuery As String) As List(Of String)  
       Dim nestLevel As Integer = 0  
       Dim blnQuoteOpen As Boolean = False  
       Dim lstReturn As New List(Of String)  
       Dim iIndex As Integer = 0  
       Dim strWord As String = ""  
       Dim queries As String() = SourceQuery.ToLower.Split(New String() {"union"}, StringSplitOptions.None)  
       For Each query As String In queries  
         iIndex = 0  
         strWord = ""
         blnQuoteOpen = False  
         For Each c As Char In query  
           iIndex += 1  
           If c = "'"c And blnQuoteOpen = False Then  
             blnQuoteOpen = True  
           Else  
             If c = "'"c And blnQuoteOpen = True Then  
               blnQuoteOpen = False  
             End If  
           End If  
           If c = "(" AndAlso blnQuoteOpen = False Then  
             nestLevel += 1  
           End If  
           If c = ")" AndAlso blnQuoteOpen = False Then  
             nestLevel -= 1  
           End If  
           If c = " "c Then  
             strWord = ""  
           Else  
             strWord &= c  
           End If  
           If strWord.ToLower = "from" And nestLevel = 0 Then  
             lstReturn.Add(Mid(query, iIndex - 3, query.Length - (iIndex - 4)))  
             Exit For  
           End If  
         Next  
       Next  
       Return lstReturn  
     End Function  

No comments:

Post a Comment