10
\$\begingroup\$

Aim: To Assess if one, or more, examples of a value exists in a Database in the quickest time as I only needs a True/False result.

The variable is Alphanumeric.

Question: Is this the quickest and best way to do this?

Public Function PrcCheckIfValueExists(vVariable As String) As String
        'Here we check if the Value Exists in the database 
        Try
            Dim ConnectionString As String = System.Configuration.ConfigurationManager.ConnectionStrings("SQLLocal").ToString()
            Using connection = New SqlConnection(ConnectionString)
                Using command As New SqlCommand("SELECT TOP 1 ID FROM TblTable WHERE ID= '" & vVariable & "'", connection)
                    connection.Open()
                    Dim result = command.ExecuteScalar()
                    connection.Close()
                    If result = "" Then
                        Return False
                    Else
                        Return True
                    End If
                End Using
            End Using

        Catch ex As Exception
            Return False
        End Try

    End Function
\$\endgroup\$
2
  • \$\begingroup\$ Why does the code return Booleans when the signature suggests it should return a string? \$\endgroup\$ Jul 1, 2014 at 7:33
  • \$\begingroup\$ Incoming is string outgoing is variable. Should I use As Boolean as last part of the first line? \$\endgroup\$ Jul 1, 2014 at 13:07

4 Answers 4

11
\$\begingroup\$
  1. This code is open to injection. Consider what happens if I pass sometext'; Drop Table TblTable; -- into that variable. Use a proper parameterized query instead.
  2. The SQL statement itself is about as efficient as it can be to my knowledge. A count would add extra overhead. Using an Exists might garner you a negligible amount of performance at the cost of readability. (Exists wouldn't need to return any value at all except what you tell it.)
  3. You could simplify your return statement by using IsNullOrEmpty()

Instead of:

                If result = "" Then
                    Return False
                Else
                    Return True
                End If

You could just use this:

Return Not String.IsNullOrEmpty(result)
\$\endgroup\$
2
  • \$\begingroup\$ no Semi-Colons in VB...LOL \$\endgroup\$
    – Malachi
    Jun 30, 2014 at 15:20
  • 2
    \$\begingroup\$ Also you need to add a Not in there to keep the false return value on empty string. \$\endgroup\$
    – Snowbody
    Jun 30, 2014 at 15:31
10
\$\begingroup\$

You should use Command parameters instead of string concatenation to avoid SQL injection attacks

 command.Parameters.Add("@ID", SqlDbType.NVarChar) ' this might not be the appropriate type
 command.Parameters("@ID").Value = vVariable

The connection will be closed after the using statement, so you don't need to close it explicitly

connection.Close() 'delete this line, it is redundant 

vVariable is not good for a variable name, because every variable is a variable, ID might be a good choice here

\$\endgroup\$
1
  • \$\begingroup\$ I should of mentioned the value derived from clicking on a value however I will change it for good practice, thanks. \$\endgroup\$ Jun 30, 2014 at 14:20
4
\$\begingroup\$

In your SQL, use EXISTS instead of TOP 1 ID. It might be faster, but would probably be impossible to measure the difference. But it better expresses what you are interested in. And it certainly won't be slower.

\$\endgroup\$
2
\$\begingroup\$

The safer way to do this is to actually call a stored procedure.

Separation of Concerns.

This is the line of code that I am talking about

Using command As New SqlCommand("SELECT TOP 1 ID FROM TblTable WHERE ID= '" & vVariable & "'", connection)

The code doesn't need to know how the database query is retrieving the information.

The stored procedure will run just as efficiently or faster, because the database will know about the procedure before it is run and have a "game plan" for it before it is called.

The variable should stay a variable all the way to the stored procedure.


you can remove the connection.Close() and move the if statement outside of the Try Catch like this

Try
    Dim ConnectionString As String = System.Configuration.ConfigurationManager.ConnectionStrings("SQLLocal").ToString()
    Using connection = New SqlConnection(ConnectionString)
        Using command As New SqlCommand("SELECT TOP 1 ID FROM TblTable WHERE ID= '" & vVariable & "'", connection)
            connection.Open()
            Dim result = command.ExecuteScalar()
        End Using
    End Using
Catch ex As Exception
    Return False
End Try
If result = "" Then 
    Return False
Else
    Return True
End If

or you can get rid of the if else and the variable declaration altogether

Try
    Dim ConnectionString As String = System.Configuration.ConfigurationManager.ConnectionStrings("SQLLocal").ToString()
    Using connection = New SqlConnection(ConnectionString)
        connection.Open()
        Using command As New SqlCommand("SELECT TOP 1 ID FROM TblTable WHERE ID= '" & vVariable & "'", connection)
            Return Not String.IsNullOrEmpty(command.ExecuteScalar()) 
        End Using
    End Using
Catch ex As Exception
    Return False
End Try

You will save a little bit when you nix the Variable creation



I somewhat agree with MrCochese.

If the code was returning a list of information with no input parameters needed, then I would say just use the string, but this code is asking for a very specific piece of information and needs a piece of input.

The code(application) gathers the input, sends it to the database. The database looks for the specified piece of information and returns it to the code(application). This shows a separation of concerns (there are two things happening here), input and query.

In the example of returning a simple set of information, only one things is happening, the return of information. There is no input or place for injection to occur.

so I stand by what I said about using a stored procedure, or better yet a user defined function because only one specific piece of information is being returned

\$\endgroup\$
14
  • 1
    \$\begingroup\$ This is a horrible idea, as you're just introduced an external dependency that is not versioned with your code. Don't do this - let SQL do the job it was created for. \$\endgroup\$
    – Mr Cochese
    Jun 30, 2014 at 15:47
  • 1
    \$\begingroup\$ The SQL is still doing the SQL stuff, I left the Query String in the code because that is what the OP has there. I mentioned the fact that there should be a stored procedure on the database that is called using a parameter, that still stands. I haven't taken anything away from the database, it's really the opposite I have given back to the database what should rightfully be there @MrCochese \$\endgroup\$
    – Malachi
    Jun 30, 2014 at 18:26
  • 1
    \$\begingroup\$ @MrCochese If the schema changes in a way that the sproc needs to change, it could be changed without OP recompiling the code. That's why stored procedures are there to begin with. \$\endgroup\$
    – RubberDuck
    Jun 30, 2014 at 18:52
  • 1
    \$\begingroup\$ Well, it is Code Review! \$\endgroup\$
    – Mr Cochese
    Jun 30, 2014 at 20:52
  • 1
    \$\begingroup\$ @MrCochese - Then maybe you could post it as a comment under the correct portion, so the OP might have a better chance of being notified/reading it. \$\endgroup\$
    – JohnP
    Jun 30, 2014 at 21:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.