0

I'm setting up a program to write log entries to a database that tracks who created the entry, what type of entry it is, the entry itself, the open date, close date (If already closed), current status and the risk to the company in question.

I am basing this program on a tutorial series found here: https://www.youtube.com/playlist?list=PLy4rL7t3MquXKhooLi3naV5F8OyMYSe8F and am using VB Toolbox's SQLControl class to actually execute the queries.

The problem is that the code works fine for adding a new user to a separate table in the database but for the log entry table, I get the above error.

The database is SQL Server Express based and was built with SSMS. I have been working with a friend who's a database designer by trade to get the database itself stood up but they aren't sure why I'm getting this error either. I've tried the original execute query based on VB Toolbox's tutorial and I also tried adding DECLARE statements at the beginning of the execution query to see if that would resolve the problem, which I suppose it did, but then it seemed to overwrite the values I had passed as parameters at the beginning of the procedure and gave me a null value error when it reached a field that couldn't be null. I've searched Stack Overflow and other coding forums for solutions but everything I've found is centered around building the queries within SSMS itself or where the only answers are "Make sure you're declaring your parameters correctly" which isn't helpful because from everything I'm seeing, the log entry procedure should work because I didn't make any changes to the SQLControl class which actually drives all of the queries and parameter definitions. When I enter a value in the query to replace it, such as NULL since the field will accept null values, I just get the same error on the next parameter, so there has to be a disconnect somewhere but I can't think of where it could be.

Working code from VB Toolbox's Tutorial:

With SQL
            .AddParam("@FirstName", firstNameTB.Text)
            .AddParam("@LastName", lastNameTB.Text)
            .AddParam("@Title", jobTitleTB.Text)
            .AddParam("@Company", companyCB.Text)
            .AddParam("@OfficeNum", offNumTB.Text)
            .AddParam("@CellNum", cellNumTB.Text)
            .AddParam("@EmailAddress", emailTB.Text)
            .AddParam("@Username", userTB.Text)
            .AddParam("@TempPassword", passTB.Text)

            .ExecQuery("INSERT INTO dbo.TeamMembers (FirstName, LastName, Title, Company, OfficeNum, CellNum, EmailAddress, Username, TempPassword) " &
                        "VALUES (@FirstName, @LastName, @Title, @Company, @OfficeNum, @CellNum, @EmailAddress, @Username, @TempPassword);")
            'Report And Abort on Error
            If .HasException(True) Then Exit Sub

            If SQL.DBDT.Rows.Count > 0 Then
                Dim r As DataRow = SQL.DBDT.Rows(0)
                MsgBox(r("LastID").ToString)
            End If

            MsgBox("User added successfully.")
        End With

Code that throws the error:

With SQL
            .AddParam("@MemberName", cbxTeamMembers.Text)
            .AddParam("@EntryType", cbxEntryType.Text)
            .AddParam("@ClaimNum", tbClaimID.Text)
            .AddParam("@StatusType", cbxStatus.Text)
            .AddParam("@LogEntry", tbEntry.Text)
            .AddParam("@OpenDate", dtpOpened.Value)
            .AddParam("@Risk", tbRisk.Text)
            If dtpClosed.Enabled = True Then
                .AddParam("@CloseDate", dtpClosed.Value)
            Else
                .AddParam("@CloseDate", "NULL")
            End If

            Dim MemberID As Integer, EntryID As Integer, StatusID As Integer

            .ExecQuery("SELECT ID FROM dbo.TeamMembers tm WHERE CONCAT(tm.FirstName, ' ', tm.LastName) = @MemberName;")
            For Each r As DataRow In .DBDT.Rows
                MemberID = r("ID")
            Next

            .ExecQuery("SELECT ID FROM dbo.EntryType et WHERE et.Description = @EntryType;")
            For Each r As DataRow In .DBDT.Rows
                EntryID = r("ID")
            Next

            .ExecQuery("SELECT ID FROM dbo.StatusTable s WHERE s.Description = @StatusType;")
            For Each r As DataRow In .DBDT.Rows
                StatusID = r("ID")
            Next

            .ExecQuery("INSERT INTO dbo.DailyLog(MemberID, TypeID, ClaimNumber, Notes, StatusID, DateOpen, DateClosed, Risk) " &
                       "VALUES (" & MemberID & "," & EntryID & ",@ClaimNum,@LogEntry," & StatusID & ",@OpenDate,@CloseDate,@Risk);")

            If .HasException(True) Then Exit Sub
        End With

Modified query that overrode previous parameters:

.ExecQuery("DECLARE @MemberName varchar(50); DECLARE @ClaimNum varchar(50); DECLARE @LogEntry varchar(max); DECLARE @OpenDate Date; DECLARE @CloseDate Date; DECLARE @Risk varchar(max); " &
                       "INSERT INTO dbo.DailyLog(MemberID, TypeID, ClaimNumber, Notes, StatusID, DateOpen, DateClosed, Risk) " &
                       "VALUES (" & MemberID & "," & EntryID & ",@ClaimNum,@LogEntry," & StatusID & ",@OpenDate,@CloseDate,@Risk);")

Execution and parameter procedure:

Public Sub ExecQuery(Query As String, Optional ReturnIdent As Boolean = False)
        RecordCount = 0
        Exception = ""

        Try
            DBCon.Open()

            DBCmd = New SqlCommand(Query, DBCon)

            Params.ForEach(Sub(p) DBCmd.Parameters.Add(p))

            Params.Clear()

            DBDT = New DataTable
            DBDA = New SqlDataAdapter(DBCmd)
            RecordCount = DBDA.Fill(DBDT)

            If ReturnIdent = True Then
                Dim RetQuery As String = "SELECT @@IDENTITY AS LastID;"

                DBCmd = New SqlCommand(RetQuery, DBCon)
                DBDT = New DataTable
                DBDA = New SqlDataAdapter(DBCmd)
                RecordCount = DBDA.Fill(DBDT)
            End If
        Catch ex As Exception
            Exception = "ExecQuery Error: " & vbNewLine & ex.Message
        Finally
            If DBCon.State = ConnectionState.Open Then DBCon.Close()
        End Try
    End Sub

    Public Sub AddParam(Name As String, Value As Object)
        Dim NewParam As New SqlParameter(Name, Value)
        Params.Add(NewParam)
    End Sub

When I based the log entry procedure off of the add user procedure from the tutorial, I had expected this procedure to enter the new entry data into the database table but I keep getting the Must declare Scalar Variable @ClaimNUm error only on this procedure, never on the New User procedure built in the tutorial this is based on. Any help on this would be greatly apprecaited.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
TOTM
  • 107
  • 7
  • 2
    Always use parameters to avoid sql injection and formatting errors. – LarsTech May 29 '19 at 15:24
  • 1
    Always use parameterized sql and avoid string concatenation to add values to sql statements. See [How can I add user-supplied input to an SQL statement?](https://stackoverflow.com/q/35163361/1260204), and [Exploits of a Mom](https://xkcd.com/327/). – Igor May 29 '19 at 15:30
  • Possible duplicate of [How can I add user-supplied input to an SQL statement?](https://stackoverflow.com/questions/35163361/how-can-i-add-user-supplied-input-to-an-sql-statement) – Igor May 29 '19 at 15:30
  • This is not a duplicate of that and I am using parameters to input into the database, that's where this problem is coming from. The MemberID and EntryID variables have already been cleaned because they were populated by a separate query and then passed to the variable. No need to redeclare at that point. – TOTM May 29 '19 at 15:32
  • Are you expecting only one values returned from those SELECT queries? Because that is all that you can put into *one* scalar variable, e.g. `MemberID`. – Andrew Morton May 29 '19 at 15:33
  • @Andrew That would cause a different error I think since the issue seems to be with the declaration, but as I stated in my original question, I'm not sure why there's a declaration error since this is modeled off of the procedure from VB Toolbox's tutorial that I linked to above. – TOTM May 29 '19 at 15:39
  • @SteveJoppich You may find that any suggestions are *not* based on us watching three hours of video, so could you could add the `ExecQuery` code to the question please? – Andrew Morton May 29 '19 at 15:44
  • @Andrew Added that and the parameter procedure used to declare the parameters. For the record, I wasn't trying to be sarcastic. I understand that I am a beginner without years or decades of professional experience however I am trying to learn so perhaps if you had explained why it looked as though I was trying to pass multiple values into one Scalar Variable I would have understood your question better. I'm not going to see things the same way a professional does and I'm not always going to catch what is implied or expected to be common knowledge, because I'm still learning what that is. – TOTM May 29 '19 at 15:56
  • Looks to me that you clear the parameters in the ExecQuery call. When you call ExecQuery again, you don't have any parameters anymore. – LarsTech May 29 '19 at 16:00
  • @Lars That was exactly it and I'm pretty dumbstruck that I missed that given the hours I've spent staring at this since Monday. I can pull this down or if you want to put it as an answer I can give you the reputation for pointing it out. – TOTM May 29 '19 at 16:08
  • @SteveJoppich It can take a little while to narrow down where the problem is. My comment about the one value was because it's something that I've seen can catch people out before - it wasn't the subject of the question, but we might have had to expand on it to get to a complete solution. Anyway, I see LarsTech's lightning reflexes spotted the problem as soon as the additional code was posted. – Andrew Morton May 29 '19 at 17:16

0 Answers0