Can't generate a StockID above 10 - sql

This is the code that tries to grab the largest StockID from the database (Access database) , but my problem is that it generates StockID's up to "S10", after this it simply doesn't increment any further. This is the subroutine that generates the StockID:
Sub generate_Stock_ID()
Dim Stock_start As String = "S"
Dim Stock_Gen As String = "SELECT MAX(StockID) FROM tblStock WHERE StockID LIKE '" & Stock_start & "%%%' "
Dim da As OleDbDataAdapter = New OleDbDataAdapter(Stock_Gen, conn)
Dim ds As DataSet = New DataSet
da.Fill(ds, "StockID")
Dim dt As DataTable = ds.Tables("StockID")
Dim count As Integer = ds.Tables("StockID").Rows.Count
If ds.Tables("StockID").rows.count = 0 Then
StockID = "S1"
Else
StockID = ds.Tables("StockID").Rows(0).Item(0)
StockID = StockID.Substring(1, (StockID.Length - 1))
StockID = Stock_start & (StockID + 1)
End If
End Sub
Screenshot of my database
Note* there are multiple ID's for various other subroutines which all share the same incrementation issue, so if i fix this i fix the other ones too. So at the moment i think my problem lies in the syntax of my SQL statement, but im open to suggestions.
Thanks!

Don't treat an Integer as String. Otherwese MAX or ORDER BY will use lexicographical instead of numerical order which means that S11 is "lower" than S2.
So you should make this column an int-column and prepend S only where you display it. Then MAX(StockID) returns an Integer, you just have to cast it and add 1:
Using conn As New OleDbConnection("Connection-String")
Using cmd As New OleDbCommand(Stock_Gen, conn)
conn.Open()
Dim stockIDObj As Object = cmd.ExecuteScalar()
If stockIDObj IsNot Nothing Then
Dim maxStockId As Int32 = DirectCast(stockIDObj, Int32)
maxStockId += 1
' ...... '
End If
End Using
End Using
You should also change OPTION STRICT to ON. Then this would never compile since the same variable cannot be used for an Object, String and Integer which is very good since it prevents errors.
If you want to keep it as string you have to cast the substring always in the database which is less readable and less efficient. I also don't know how to do it in access.
If you want to change the type of column in an already populated table you should first add a new column with a similar name which is of type int. If all have S at the beginning you could first remove that, then you can update the new column with the casted int value. Finally you can delete the old column and rename the new to the old.

The root of this issue that StockID is a STRING and 'S1'>'S10' so for all StockId > 10 you get max = 'S1'.
As a fast fix try to change MAX(StockID) to:
SELECT 'S'+CAST(MAX(CAST(SUBSTRING(StockID,2,100) as int)) as varchar(100))
For ACCESS DB try to use:
SELECT "S" & cstr(MAX(CINT(MID(StockID,2,100))))

Related

Excel to VB: Can't read the zero behind

I'm doing a connection with excel and I have a problem when I try to use an ID that have 0 behind...
I'm using a ListBox and add the IDs from the excel's worksheet as items. IDs have 9 numbers, like "123456789" or "098765430". So that I remove the last 4 characters to search the IDs with the same 5 numbers and add in another ListBox. It works fine, except with the codes with 0 (zero) behind.
Dim ConnectionString As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0; Data Source=" & Application.StartupPath & "\Tabela_Precos.xlsx; Extended Properties=Excel 12.0;")
ConnectionString.Open()
Dim ds As New DataSet
Dim dt As New DataTable
ds.Tables.Add(dt)
Dim da
For i = 0 To Form1.ListBox1.Items.Count - 1
Dim str As String = Compras.ListBox1.Items(i).ToString
Dim prod As String = str.Remove(str.Length - 4)
da = New OleDbDataAdapter("SELECT * FROM [Sheet1$] WHERE ID like '%" & prod & "%'", ConnectionString)
ListBox1.Items.Add(dt.Rows(i).Item(0))
Next
Your Excel file has the ID column entered as integer values, but is formatted for left-zero padding to present as a nine character field. Your Excel db connection is reading the values as numbers (type Double, even-though they are integers). Your original select statement is implicitly convert ID to a string for the Like comparison; however, this conversion does not now you want left-zero padding. To use this type of comparison, you need to format ID yourself.
Select * From [sheet1$] Where (Format([ID], ""000000000"") Like '" & prod & "%')"
As you have indicated in the comments above, this works. However, it is not the most efficient in terms of speed. Since ID is numeric, it should be faster to do a numeric comparison. You have already defined a String variable named prod and the following solution uses that variable to prepare a numeric value for use in constructing an alternate select based on your criteria.
Dim prodNum As Int32 = Int32.Parse(prod) * 10000I
Then the Select statement would become:
"Select * From [sheet1$] Where ((([ID]\10000) * 10000)=" & prodNum.ToString & ")"
These examples use a concatenated select statement, and ideally you would not do it this way, but rather use a parameterized statement with replacement values. I'll leave that exercise up to you to perform.

SQL variable returning 0

When I run the following SQL statement in SQL Server Management Studio it returns a count of 2
SELECT COUNT(*)
FROM Daisy_Copy2
WHERE ChargeCode = '1';
But for some reason when I run the following VB.net code the result variable returns a 0 and doesn't identify that duplicate codes exist.
Dim result As Integer
Using cmdb = New SqlCommand("SELECT COUNT(*) FROM Daisy_Copy2 WHERE ChargeCode = '1'", conn)
Int(result = cmdb.ExecuteScalar())
If result > 1 Then
MessageBox.Show("Duplicate Codes Exist!", "Billing", _
MessageBoxButtons.OK, MessageBoxIcon.Information)
Else
MsgBox(result)
End If
End Using
Can anyone help me understand why?
Any help greatly appreciated.
Instead of ExecuteNonQuery you should use ExecuteScalar
Dim result As Integer = CInt(cmd.ExecuteScalar())
ExecuteNonQuery is normally used for updates or inserts that don't leave a result, so it returns an integer telling you how many rows were affected, not the result itself.
What you most likely are meaning to use is ExecuteScalar which returns the first column of the first row in the result set returned by the query, in this case the integer containing your count.
this is just a way you can use:
Dim Sqlda = New SqlDataAdapter("SELECT COUNT(*) AS tCount FROM Daisy_Copy2 WHERE ChargeCode=1", conn)
Dim sqlds = New DataSet
Sqlda.Fill(sqlds, "Daisy_Copy2")
Dim tblRow As DataRow
For Each tblRow In sqlds.Tables("Daisy_Copy2").Rows
MsgBox(tblRow("tCount").ToString())
Next
use below link to read more about it
System.Data.SqlClient Namespace
Good luck

Query for sum of column values not giving me a value

I have a GridView in my ASP Page where the user can change one of the values and the other is a read only value. I want that when the row is updated a query will execute that sums the value of one column to the other and changes it. Ex... Value1 + Value 2 = Value2. I wrote this in the code-behind:
Protected Sub GridView1_RowUpdated(sender As Object, e As EventArgs) Handles GridView1.RowUpdated
Dim connectionString As String = "mystring"
Using cn As New SqlConnection(connectionString)
Dim cmd As New SqlCommand()
cmd = New SqlCommand("Select (Purchased + Actual) as Actual from Product", cn)
cn.Open()
cmd.ExecuteNonQuery()
cn.Close()
End Using
yet the value doesn't sum. A part of me says I need an update command to save the value or something like that but what I read in W3 and other places doesn't point me to that. I guess since there's different products (of course) I need a WHERE ProductID = #Parameter... right? Still that code should change the rest of the values and it doesn't. Any pointers or anything that flew over me? Thanks a bunch!
Looks like you want
Update Product Set Value2 = Value1 + Value2
Where ProductId = #Parameter

unable to find specified column in result set index out of bounds index out of range exception

i am having trouble putting a value in a textbox. Each time a ticket is sold i put the total price in a textbox, each time a ticket is sold for the same concert it increases by adding its self to the total price. It works at the first sale, but after that it breaks down. here is the code and thanks in advance.
Private Function DisplayMoneyTaken() As Integer
Dim totalMoney As Integer
'open the database connection
strSQL = "SELECT MAX(Total_Money) FROM Sales WHERE Concert_Id =" + Mid(cboVenue.Text, 1, 4)
conn.Open()
cmd.Connection = conn
cmd.CommandText = strSQL
cmd.CommandType = CommandType.Text
dr = cmd.ExecuteReader()
'read the record returned
dr.Read()
If IsDBNull(dr.Item(0)) Then
totalMoney = txtPrice.Text
Else
DisplayMoneyTaken = dr.Item("Total_Money") + Val(txtPrice.Text)
End If
'close the database
conn.Close()
Return totalMoney
End Function
It doesn't appear that your query has a column named "Total_Money". You didn't name the single column your query returns.
Michael,
When using an aggregate function, it is necessary to also assign an alias to that column.
For example
strSQL = "SELECT MAX(Total_Money) as CaChing FROM Sales WHERE Concert_Id =" + Mid(cboVenue.Text, 1, 4)
If you do not assign an alias, the server will sometimes assign one. But you have to know or guess what it will be. Its a lot better to just pick one that makes sense.
You can also index items with a number, this is what you did when you were checking for NULLs.
This same syntax could have been used when accessing the value.
DisplayMoneyTaken = dr.Item(0) + Val(txtPrice.Text)

Sorting numbers in Access and .NET

I have an Access table which has a Number field and a Text field.
I can run a query like this:
SELECT * FROM Table ORDER BY intID ASC
//outputs 1,2,3,10
But when I try to run the same query through the .NET OleDB client, like this:
Private Sub GetData()
Using cnDB As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Path)
cnDB.Open()
Dim SQL As String = "SELECT * FROM Table ORDER BY intID ASC"
Dim cmd As New OleDbCommand(SQL, cnDB)
Dim dr As OleDbDataReader = cmd.ExecuteReader()
While dr.Read()
lst.Items.Add(dr.Item("intID") & " - " & dr.Item("strName"))
End While
cnDB.Close()
End Using
End Sub
I get items in the order 1,10,2,3.
What's going on here, and how can I have the data sort "naturally" (1,2,3,10) in both places?
try
SELECT * FROM Table ORDER BY CInt(intID) ASC
to explicitly tell Access to treat this as an integer and not a string. Obviously, something in the OleDbClient is seeing this field as a string (text field) and sorting accordingly.
I suspect the problem is your connection string. If you're connecting to an Access database and include IMEX=1 in your connection string, the provider will treat all data as string. As such, the ordering will order by the string value, giving you 1, 10, 2, 3, as opposed to leaving the intID as an integer, and ordering it in numerical order.
It looks like you're getting a lexical (alphabetic) order. This will be correct if something in your database or query thinks that is a varchar/text column type instead of a numeric type.