0

I have the stored procedure below:

ALTER PROCEDURE [dbo].[GetGrossIncome]
@Date1 date, @Date2 date, @GrossTotal int OUTPUT
AS
BEGIN

SELECT @GrossTotal =  sum(GrandTotal) From ClientInvoicedItems where (InvoicePaidStatus ='FULLY PAID' and (Date >=@date1 and Date <=@Date2)) group by GrandTotal 

END

What I want is to calculate the total value in the 'GrandTotal' Column for the date range selected and then save the value in a textbox. Below is the VB code:

 Private Sub GetTotalIncome()
    Dim conn_String As String
    conn_String = "Data Source=Server-Pc;Initial Catalog=AWInformationSystem;Persist Security Info=True;User ID=sa;Password=password1"
    Dim Mycon = New SqlConnection(conn_String)
    ' Dim cmd = New SqlCommand("GetGrossIncome", Mycon)
    ' Dim dAdapter = New SqlDataAdapter(cmd)

    Mycon.Open()
    Dim cmd As SqlCommand = New SqlCommand("GetGrossIncome", Mycon)
    cmd.CommandType = CommandType.StoredProcedure
    cmd.Parameters.AddWithValue("@date1", TxtDateTo.Text)
    cmd.Parameters.AddWithValue("@date2", TxtDateFrom.Text)
    cmd.Parameters.Add("@GrossTotal", SqlDbType.Int, 500)
    cmd.Parameters("@GrossTotal").Direction = ParameterDirection.Output
    cmd.ExecuteNonQuery()
    'If Not IsDBNull(cmd.Parameters("@GrossTotal")) Then
    TxtGrossIncome.Text = (cmd.Parameters("@GrossTotal").Value())
    '  End If

    Mycon.Close()

End Sub

When i run the code, if i select the same date as the start and end date, i get a value in the text box but its always the wrong value. when I select a different start date and end date i get an error: 'System.InvalidCastException: 'Conversion from type 'DBNull' to type 'String' is not valid.'

A pointer to the right direction is welcome, thanks in advance.

Samuel Ronald
  • 55
  • 1
  • 1
  • 6
  • ````Conversion from type DBNull to type String is not valid.```` is telling you the error. ````DBNull```` is the value of what's being returned from your stored proc, given those scenarios. I'd debug, get the values of ````TxtDateTo.Text```` and ````TxtDateFrom.Text```` and manually run the stored proc if you can. – JohnPete22 Feb 04 '21 at 13:51
  • I'd also post your stored proc as well, as that is most likely the culprit for the error. Not the VB.net code. – JohnPete22 Feb 04 '21 at 13:53
  • I did post the stored procedure – Samuel Ronald Feb 04 '21 at 14:01
  • 1
    The DBNull conversion error is because you've commented out the null check. DBNull will be returned if no rows qualify. Regarding wrong results, it may be because you are passing string parameters instead of dates. [Avoid AddWithValue](https://www.dbdelta.com/addwithvalue-is-evil/) and pass a strongly-typed DateTime parameter. – Dan Guzman Feb 04 '21 at 14:02
  • `TxtDateTo.Text` suggests a (free type) text box is being used, rather than a date picker as well. That means that a user *could* enter a value like `04/02/2020` and you wouldn't know if they mean 04 February 2020 or 02 April 2020. For dates, you are often best enforcing the input format (which is unambiguous), or using a (date) picker. – Thom A Feb 04 '21 at 14:05
  • I'd update your SQL proc to have an IF statement, or potentially a ````COALESCE```` to return a default value in the scenario no rows meet the criteria. You can then check for that specific case in your code and output a message. – JohnPete22 Feb 04 '21 at 14:05
  • @DanGuzman I am using 2 datetimepickers in the front end to select the dates. I commented out the null check because i still got the same error even when it wasn't commented out. – Samuel Ronald Feb 04 '21 at 14:14
  • @Larnu I am using a datetimepicker control to select the dates. – Samuel Ronald Feb 04 '21 at 14:15
  • @JohnPete22 Would you be kind to provide an example am afraid I am not to good, i have just started using stored procedures. – Samuel Ronald Feb 04 '21 at 14:16
  • Aside: You should be disposing your connection and command objects with `Using` blocks. And [please stop using AddWithValue](https://www.dbdelta.com/addwithvalue-is-evil/) – Charlieface Feb 04 '21 at 14:50
  • @SamuelRonald something like this in your proc ````COALESCE(sum(GrandTotal), -1)```` and then in your code, you will specifically look for the -1 and output a message. https://www.w3schools.com/sql/func_sqlserver_coalesce.asp – JohnPete22 Feb 04 '21 at 15:17
  • @SamuelRonald. make sure you pass dateTimePicker.Value instead of Text. – Dan Guzman Feb 04 '21 at 16:17

3 Answers3

1

I'm not sure on the same-day incorrect value, but this is why you're getting the null error:

cmd.Parameters.AddWithValue("@date1", TxtDateTo.Text)
cmd.Parameters.AddWithValue("@date2", TxtDateFrom.Text)

(Date >=@date1 and Date <=@Date2))

Your dates are transposed. @date1 should be TxtDateFrom, and @date2 should be TxtDateTo. For an example, in your current code a from date of 2021-02-01 and a to date of 2021-02-03 would become this SQL filter:

(Date >='2021-02-03' and Date <='2021-02-01'))

Since that's impossible, it's returning no result.

bt224
  • 146
  • 1
  • 5
1

Some database objects like connections and commands need to disposed. Using...End Using blocks handle this even if there is an error.

Don't open the connection until directly before the .Execute...

Don't use .AddWithValue with Sql Server. See http://www.dbdelta.com/addwithvalue-is-evil/ and https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/ and another one: https://dba.stackexchange.com/questions/195937/addwithvalue-performance-and-plan-cache-implications Here is another https://andrevdm.blogspot.com/2010/12/parameterised-queriesdont-use.html

I have separated the user interface code in the button and the data access code in the function. All the validation of input and message boxes are in the button code.

I am not sure if parameter names are case sensitive in Sql Server but, just for grins, I made them match. @date1 -> @Date1 etc. I don't think you need the Group By phrase in the stored procedure since Sum() is the only element in the Select.

You do not need to check for null because Sum() will return 0 even if no records match the criteria.

Private Function GetTotalIncome(startDate As Date, endDate As Date) As Integer
    Dim TotalIncome As Integer
    Dim conn_String = "Data Source=Server-Pc;Initial Catalog=AWInformationSystem;Persist Security Info=True;User ID=sa;Password=password1"
    Using Mycon = New SqlConnection(conn_String),
            cmd As SqlCommand = New SqlCommand("GetGrossIncome", Mycon)
        cmd.CommandType = CommandType.StoredProcedure
        cmd.Parameters.Add("@Date1", SqlDbType.Date).Value = startDate
        cmd.Parameters.Add("@Date2", SqlDbType.Date).Value = endDate
        cmd.Parameters.Add("@GrossTotal", SqlDbType.Int)
        cmd.Parameters("@GrossTotal").Direction = ParameterDirection.Output
        Mycon.Open()
        cmd.ExecuteNonQuery()
        TotalIncome = CInt(cmd.Parameters("@GrossTotal").Value)
    End Using
    Return TotalIncome
End Function

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    Dim Date1, Date2 As Date

    If Not Date.TryParse(TxtDateFrom.Text, Date1) Then 'Start Date
        MessageBox.Show("Please enter a valid date in the From box")
        Exit Sub
    End If
    If Not Date.TryParse(TxtDateTo.Text, Date2) Then 'End Date
        MessageBox.Show("Please enter a valid date in the To box.")
        Exit Sub
    End If
    If Date1 > Date2 Then
        MessageBox.Show("The start date cannot be greater than the end date.")
        Exit Sub
    End If
    TxtGrossIncome.Text = GetTotalIncome(Date1, Date2).ToString
End Sub
Mary
  • 14,926
  • 3
  • 18
  • 27
0

So i managed to get both sets of codes working. Thanks to suggestions from members. The stored procedure was wrongly written, below is the correct one. Thanks to the solution in this link: How to do sum of col results from a SQL Stored Procedure.

ALTER PROCEDURE [dbo].[GetGrossIncome]
@Date1 date, @Date2 date, @GrossTotal int OUTPUT
AS
BEGIN

SELECT @GrossTotal  =  ISNULL(SUM(ISNULL(GrandTotal,0)),0) From 
ClientInvoicedItems 
Where (Date >=@date1 and Date <=@Date2) 

Return
    
END

The correct vb code below:

    Dim Mycon = New SqlConnection(conn_String)

    Mycon.Open()
    Dim cmd As SqlCommand = New SqlCommand
    cmd.CommandType = CommandType.StoredProcedure
    cmd.CommandText = "GetGrossIncome"
    cmd.Parameters.AddWithValue("@date1", TxtDateFrom.Text)
    cmd.Parameters.AddWithValue("@date2", TxtDateTo.Text)
    Dim sum_values As SqlParameter = New SqlParameter
    sum_values = cmd.Parameters.Add("@GrossTotal", SqlDbType.Decimal)
    sum_values.Direction = ParameterDirection.Output
    cmd.Connection = Mycon
    cmd.ExecuteNonQuery()
    Mycon.Close()
    TxtGrossIncome.Text = sum_values.Value.ToString()
Samuel Ronald
  • 55
  • 1
  • 1
  • 6
  • Where did the IsNull business come from. I didn't see it in the link you provided. I believe Sum() will return 0 even if no records match the criteria. – Mary Feb 06 '21 at 04:00
  • Please take a look at my code because you are missing the boat on closing and disposing database objects. If there is a error in `cmd.ExecuteNonQuery` how is your connection closed, let alone disposed. – Mary Feb 06 '21 at 04:03
  • @Mary I ran your code but each time it returns a value of zero no matter the date range I select. – Samuel Ronald Feb 15 '21 at 07:15