Evaluate string on record table, - vb.net

How to evaluate match on the record table with vb I have a code like this
Dim absenperintah As SqlCommand = New SqlCommand("Select * from mytable where kodetp ='109'", cekdata)
absenperintah.CommandType = CommandType.Text
cekdata.Open()
Dim valuex = "500"
Using cekbaca As SqlDataReader =
absenperintah.ExecuteReader(CommandBehavior.CloseConnection)
If cekbaca.Read = True Then
Dim nilxbaca = cekbaca("rumus_k") --> record in the table is 1906650*(3.7/100)
Dim nilmy = valuex + nilxbaca
Dim result = New DataTable().Compute(nilmy, Nothing)
MsgBox(result)
End If
cekbaca.Close()
End Using
cekdata.Close()
I get the result 185,070,546 it should be result =70,564.55
how to get result =70,564.55 from Dim nilHy = valuex + nilxbaca

Your problem is that you are declaring these numbers as strings and they are being calculated accordingly.
What you think you are doing:
500 + 1906650*(3.7/100) = 70,564.55
If you were processing these as numbers, it would perform math and your calculation would work.
However, you have declared these values as strings. Therefore the code is actually running like this:
"500" + "1906650*(3.7/100)" 'String concatenation. Not math.
5001906650*(3.7/100) = 185,070,546
Try this code instead:
Dim absenperintah As SqlCommand = New SqlCommand("Select * from mytable where kodetp ='109'", cekdata)
absenperintah.CommandType = CommandType.Text
cekdata.Open()
Dim valuex = "500"
Using cekbaca As SqlDataReader =
absenperintah.ExecuteReader (CommandBehavior.CloseConnection)
If cekbaca.Read = True Then
Dim nilxbaca = cekbaca("rumus_k") 'record in the table is "1906650*(3.7/100)"
Dim nilmy = valuex & " + " & nilxbaca 'makes "500 + 1906650*(3.7/100)"
'Note: your next line of code, DataTable.Compute() will evaluate a
' (string) formula over several rows.
Dim result = New DataTable().Compute(nilmy, Nothing)
'Based on this code here, you are only processing one row.
'Maybe .Compute() is totally unnecessary here.
'You would be better to say: result = 500 + nilxbaca
' or maybe declare valuex as integer, to help the compiler treat it like a number instead of a string.
' or maybe your original code did apply this formula over several rows.
' ... In that case, my example would fix your Compute() formula.
MsgBox(result)
End If
cekbaca.Close()
End Using
cekdata.Close()

Related

How to increment number with current year + character string?

Public Sub incrPR()
Dim curValue As Integer
Dim result As String
Dim yr As String = Now.Year.ToString()
Dim txt As String = "PR"
Using con As SqlConnection = New SqlConnection(ConString)
con.Open()
Dim cmd = New SqlCommand("Select MAX(SpecialOrderNo) FROM SpecialOrder", con)
result = cmd.ExecuteScalar().ToString
If String.IsNullOrEmpty(result) Then
result = "000"
End If
Int32.TryParse(result, curValue)
curValue += 1
result = curValue.ToString("D3") + "-" + yr + "-" + txt
txtno.Text = result
End Using
End Sub
Expected output:
001-2018-PR
002-2018-PR
003-2018-PR
The specific reason that you're not seeing the behaviour you want is here:
Int32.TryParse(result, curValue)
If result is "001-2018-PR" then TryParse will fail, i.e. return False, and that means that curValue will be zero. That means that you are going to get zero EVERY time. If you want to parse the first part of the text then do that rather than parsing the whole thing, e.g.
Int32.TryParse(result.Split("-"c)(0), curValue)
I would change things significantly but that will fix your immediate issue.

Set values to array and then do for each

How would I set following into array:
Public Function opcijeMp(ByVal hwid As String)
Dim hardware As String = hwid
Dim result = New List(Of String)()
Try
ManageConnection(False, konekcija) 'Open connection'
Dim strQuery As String = "SELECT * FROM info.opcije_mp as mp inner join instalacije as i where mp.idopcije_mp =
i.opcijeMP and i.instalacije_hwid = '" + Globals.cpuid + "';"
Dim SqlCmd As New MySqlCommand(strQuery, dbCon)
Dim reader As MySqlDataReader = SqlCmd.ExecuteReader()
While reader.Read()
Globals.prodaja = reader.GetString("Prodaja")
Globals.Kalkulacije = reader.GetString("Kalkulacije")
Globals.Zaduznice = reader.GetString("Zaduznice")
Globals.Predisponacije = reader.GetString("Predisponacije")
Globals.Robno = reader.GetString("Robno")
Globals.KUF = reader.GetString("KUF")
Globals.KIF = reader.GetString("KIF")
Globals.Narudzbenice = reader.GetString("Narudzbenice")
Globals.Nalozi = reader.GetString("Nalozi")
Globals.akcijskeCijene = reader.GetString("Akcijske_cijene")
Globals.servisnaRoba = reader.GetString("Servisna_roba")
Globals.Ostalo1 = reader.GetString("Ostalo1")
Globals.Ostalo2 = reader.GetString("Ostalo2")
Globals.Ostalo3 = reader.GetString("Ostalo3")
End While
reader.Close()
'Vraća podatke u Listi stringova
'Return result
Catch ex As MySqlException
Console.WriteLine("Error: " & ex.ToString())
Return Nothing
Finally
ManageConnection(True, konekcija)
End Try
End Function
So i can use it in next function with for each loop:
Dim s As String = Globals.prodaja
Dim parts As String() = s.Split(New Char() {","c})
Dim icona As String = parts(1)
Dim barmanager1 As New BarManager
Dim TileBarItem = New TileBarItem()
TileBarItem.Content = parts(3)
TileBarItem.Name = "ffss"
TileBarItem.Width = 150
Icon = New BitmapImage(New Uri("pack://application:,,,/DevExpress.Images.v16.1;component/Images/" + icona + ""))
TileBarItem.TileGlyph = Icon
TileBarItem.Background = New SolidColorBrush(DirectCast(ColorConverter.ConvertFromString(parts(2)), Color))
MessageBox.Show(parts(2))
maloprodaja.Items.Add(TileBarItem)
Right now i have to run function for each variable i have stored in global variables class, i would like to add all the results from first function to one array in Globals and then run second function with for each loop to populate my tilebar
Using an external variable like Globals to pass data around is extremely poor practice. Your first function in the question should return the data, or alternatively it should return the MySqlDataReader. That will simplify what you're trying to do later on and effectively make this problem go away.
I also so saw this:
Dim strQuery As String = "SELECT * FROM info.opcije_mp as mp inner join instalacije as i where mp.idopcije_mp =
i.opcijeMP and i.instalacije_hwid = '" + Globals.cpuid + "';"
I want to highlight this part:
" ... and i.instalacije_hwid = '" + Globals.cpuid + "';"
It's hard to understand just how bad that is. I can't think of a better way to get a program hacked. Google for parameterized queries and learn how to use them, rather than string concatentation, to put your cpuid into the sql statement.

get column names Jet OLE DB in vb.net

I've written a function which reads csv files and parametrizes them accordingly, therefore i have a function gettypessql which queries sql table at first to get data types and therefore to adjust the columns which are later inserted in sql. So my problem is when I set HDR=Yes in Jet OLE DB I get only column names like F1, F2, F3. To circumvent this issue I've set HDR=No and written some for loops but now I get only empty strings, what is actually the problem? here is my code:
Private Function GetCSVFile(ByVal file As String, ByVal min As Integer, ByVal max As Integer) As DataTable
Dim ConStr As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & TextBox1.Text & ";Extended Properties=""TEXT;HDR=NO;IMEX=1;FMT=Delimited;CharacterSet=65001"""
Dim conn As New OleDb.OleDbConnection(ConStr)
Dim dt As New DataTable
Dim da As OleDb.OleDbDataAdapter = Nothing
getData = Nothing
Try
Dim CMD As String = "Select * from " & _table & ".csv"
da = New OleDb.OleDbDataAdapter(CMD, conn)
da.Fill(min, max, dt)
getData = New DataTable(_table)
Dim firstRow As DataRow = dt.Rows(0)
For i As Integer = 0 To dt.Columns.Count - 1
Dim columnName As String = firstRow(i).ToString()
Dim newColumn As New DataColumn(columnName, mListOfTypes(i))
getData.Columns.Add(newColumn)
Next
For i As Integer = 1 To dt.Rows.Count - 1
Dim row As DataRow = dt.Rows(i)
Dim newRow As DataRow = getData.NewRow()
For j As Integer = 0 To getData.Columns.Count - 1
If row(j).GetType Is GetType(String) Then
Dim colValue As String = row(j).ToString()
colValue = ChangeEncoding(colValue)
colValue = ParseString(colValue)
colValue = ReplaceChars(colValue)
newRow(j) = colValue
Else
newRow(j) = row(j)
End If
Next
getData.Rows.Add(newRow)
Application.DoEvents()
Next
Catch ex As OleDbException
MessageBox.Show(ex.Message)
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
dt.Dispose()
da.Dispose()
End Try
Return getData
End Function
and get types sql, this one doesn't convert properly, especially doubles
Private Sub GetTypesSQL()
If (mListOfTypes Is Nothing) Then
mListOfTypes = New List(Of Type)()
End If
mListOfTypes.Clear()
Dim dtTabelShema As DataTable = db.GetDataTable("SELECT TOP 0 * FROM " & _table)
Using dtTabelShema
For Each col As DataColumn In dtTabelShema.Columns
mListOfTypes.Add(col.DataType)
Next
End Using
End Sub
I think you have made it more complicated than it needs to be. For instance, you get the dbSchema by creating an empty DataTable and harvesting the Datatypes from it. Why not just use that first table rather than creating a new table from the Types? The table also need not be reconstructed over and over for each batch of rows imported.
Generally since OleDb will try to infer types from the data, it seems unnecessary and may even get in the way in some cases. Also, you are redoing everything that OleDB does and copying data to a different DT. Given that, I'd skip the overhead OleDB imposes and work with the raw data.
This creates the destination table using the CSV column name and the Type from the Database. If the CSV is not in the same column order as those delivered in a SELECT * query, it will fail.
The following uses a class to map csv columns to db table columns so the code is not depending on the CSVs being in the same order (since they may be generated externally). My sample data CSV is not in the same order:
Public Class CSVMapItem
Public Property CSVIndex As Int32
Public Property ColName As String = ""
'optional
Public Property DataType As Type
Public Sub New(ndx As Int32, csvName As String,
dtCols As DataColumnCollection)
CSVIndex = ndx
For Each dc As DataColumn In dtCols
If String.Compare(dc.ColumnName, csvName, True) = 0 Then
ColName = dc.ColumnName
DataType = dc.DataType
Exit For
End If
Next
If String.IsNullOrEmpty(ColName) Then
Throw New ArgumentException("Cannot find column: " & csvName)
End If
End Sub
End Class
The code to parse the csv uses CSVHelper but in this case the TextFieldParser could be used since the code just reads the CSV rows into a string array.
Dim SQL = String.Format("SELECT * FROM {0} WHERE ID<0", DBTblName)
Dim rowCount As Int32 = 0
Dim totalRows As Int32 = 0
Dim sw As New Stopwatch
sw.Start()
Using dbcon As New MySqlConnection(MySQLConnStr)
Using cmd As New MySqlCommand(SQL, dbcon)
dtSample = New DataTable
dbcon.Open()
' load empty DT, create the insert command
daSample = New MySqlDataAdapter(cmd)
Dim cb = New MySqlCommandBuilder(daSample)
daSample.InsertCommand = cb.GetInsertCommand
dtSample.Load(cmd.ExecuteReader())
' dtSample is not only empty, but has the columns
' we need
Dim csvMap As New List(Of CSVMapItem)
Using sr As New StreamReader(csvfile, False),
parser = New CsvParser(sr)
' col names from CSV
Dim csvNames = parser.Read()
' create a map of CSV index to DT Columnname SEE NOTE
For n As Int32 = 0 To csvNames.Length - 1
csvMap.Add(New CSVMapItem(n, csvNames(n), dtSample.Columns))
Next
' line data read as string
Dim data As String()
data = parser.Read()
Dim dr As DataRow
Do Until data Is Nothing OrElse data.Length = 0
dr = dtSample.NewRow()
For Each item In csvMap
' optional/as needed type conversion
If item.DataType = GetType(Boolean) Then
' "1" wont convert to bool, but (int)1 will
dr(item.ColName) = Convert.ToInt32(data(item.CSVIndex).Trim)
Else
dr(item.ColName) = data(item.CSVIndex).Trim
End If
Next
dtSample.Rows.Add(dr)
rowCount += 1
data = parser.Read()
If rowCount = 50000 OrElse (data Is Nothing OrElse data.Length = 0) Then
totalRows += daSample.Update(dtSample)
' empty the table if there will be more than 100k rows
dtSample.Rows.Clear()
rowCount = 0
End If
Loop
End Using
End Using
End Using
sw.Stop()
Console.WriteLine("Parsed and imported {0} rows in {1}", totalRows,
sw.Elapsed.TotalMinutes)
The processing loop updates the DB every 50K rows in case there are many many rows. It also does it in one pass rather than reading N rows thru OleDB at a time. CsvParser will read one row at a time, so there should never be more than 50,001 rows worth of data on hand at a time.
There may be special cases to handle for type conversions as shown with If item.DataType = GetType(Boolean) Then. A Boolean column read in as "1" cant be directly passed to a Boolean column, so it is converted to integer which can. There could be other conversions such as for funky dates.
Time to process 250,001 rows: 3.7 mins. An app which needs to apply those string transforms to every single string column will take much longer. I'm pretty sure that using the CsvReader in CSVHelper you could have those applied as part of parsing to a Type.
There is a potential disaster waiting to happen since this is meant to be an all-purpose importer/scrubber.
For i As Integer = 0 To dt.Columns.Count - 1
Dim columnName As String = firstRow(i).ToString()
Dim newColumn As New DataColumn(columnName, mListOfTypes(i))
getData.Columns.Add(newColumn)
Next
Both the question and the self-answer build the new table using the column names from the CSV and the DataTypes from a SELECT * query on the destination table. So, it assumes the CSV Columns are in the same order that SELECT * will return them, and that all CSVs will always use the same names as the tables.
The answer above is marginally better in that it finds and matches based on name.
A more robust solution is to write a little utility app where a user maps a DB column name to a CSV index. Save the results to a List(Of CSVMapItem) and serialize it. There could be a whole collection of these saved to disk. Then, rather than creating a map based on dead reckoning, just deserialize the desired for user as the csvMap in the above code.

.Conversion error on unique identifier, shouldn't be referenced at all?

I'm working on the shopping cart for a website, I have this function that retrieves a voucher from my database:
Public Shared Function CheckForVoucher(ByVal strVoucherName As String) As DataTable
Dim connect As New SqlConnection
Dim Data As New DataTable ''Connection works, finds number of Vouchers in DB that match either code or ID. ID to be used for randomly generated vouchers.
connect.ConnectionString = "SERVER = SERVER-SQL01; Trusted_Connection=yes; DATABASE=PCSQL"
connect.Open()
Dim query As String
Dim search As String
search = strVoucherName
If search.Length >= 25 Then
query = "SELECT * from PCSQL.dbo.X_WW_VOUCHER_DETAILS WHERE vID='" & search & "' "
Else
query = "SELECT * from PCSQL.dbo.X_WW_VOUCHER_DETAILS WHERE voucherName='" & search & "' "
End If
Dim command = New SqlDataAdapter(query, connect)
command.Fill(Data)
connect.Close()
strVoucherName = query
Return Data
End Function
This all works peachy-keen on the site I'm working on. At the end of a customers order it fires another function, the increase the totalUses of the voucher by one (my boss wants to make sure that people don't spam the codes and run him out of business).
Public Shared Function addUse(ByVal strVoucherName As String, intCurrentUses As Integer) As Boolean
Dim connect As New SqlConnection
Dim data As New DataTable
connect.ConnectionString = "SERVER = SERVER-SQL01; Trusted_Connection = yes; DATABASE=PCSQL"
connect.Open()
Dim query As String
Dim name As String = strVoucherName
Dim current As Integer = intCurrentUses
Dim newint As Integer = current + 1
query = "UPDATE dbo.X_WW_VOUCHER_DETAILS SET currentUses= #currentUses WHERE voucherName=#voucherName"
Dim command As New SqlCommand(query, connect)
command.Parameters.Add("#voucherName", SqlDbType.VarChar)
command.Parameters("#voucherName").Value = name
command.Parameters.Add("#currentUses", SqlDbType.Int)
command.Parameters("#currentUses").Value = newint
command.ExecuteNonQuery()
connect.Close()
Return True
End Function
This also works fine, and I can check the SQL table in SQL SERVER and see that the "currentUses" column has increased by one. Yay.
Problem
When I test the code by submitting again, it fails if the currentUses column is equal to the validUses column. I end up the error "Conversion failed when converting from a character string to uniqueidentifier" even though the Unique Identifier is not directly referenced at all.
I've tested on a voucher that is valid 5 times. Times 1 through 4, no errors but as soon as currentUses was also 5... no go.
Why would equal columns cause my function to crap itself?
SQL Table
-vID Uniqueidentifier
-voucherName Nchar(15)
-expiryDate Date
-validUses Int
-currentUses Int
-discountType Nchar(15)
-appliesTo Nchar(15)
-numberOf Nchar(20)
-Amount Int
-noOfItems Int
-Category Nchar(100)
-freebieID Nchar(15)
-discountAmount Int
-Description Nchar(255)
EDIT
I have narrowed the error down to this if statement.
If search.Length >= 25 Then
query = "SELECT * from PCSQL.dbo.X_WW_VOUCHER_DETAILS WHERE vID='" & search & "' "
Else
query = "SELECT * from PCSQL.dbo.X_WW_VOUCHER_DETAILS WHERE voucherName='" & search & "' "
End If
The Voucher itself is called from cart.aspx using
Protected Sub btnVoucherCheck_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnVoucherCheck.Click
Dim Data As DataTable = Voucher.CheckForVoucher(txtVoucher.text)
If Data.Rows.Count > 0 Then
Dim row As DataRow
row = Data.Rows(0)
Voucher.VoucherID = row.Item("vID").ToString().Trim()
Voucher.VoucherName = row.Item("voucherName").ToString().Trim()
Voucher.ExpiryDate = row.Item("ExpiryDate")
Voucher.ValidUses = row.Item("ValidUses")
Voucher.CurrentUses = row.Item("CurrentUses")
Voucher.DiscountType = row.Item("DiscountType").ToString().Trim()
Voucher.AppliesTo = row.Item("AppliesTo").ToString().Trim()
Voucher.NumberOf = row.Item("NumberOf").ToString().Trim()
Voucher.Amount = row.Item("Amount")
Voucher.noOfItems = row.Item("NoOfItems")
Voucher.Category = row.Item("Category").ToString().Trim()
Voucher.FreebieID = row.Item("FreebieID").ToString().Trim()
Voucher.DiscountAmount = row.Item("DiscountAmount")
Dim count As Int32
count = 0
Dim expiry As DateTime = Voucher.ExpiryDate
Dim today As DateTime = Date.Today()
count = ((expiry - today).Days)
If count <= -1 Then
txtVoucher.Text = "Voucher expired"
Else 'Further checks. One: Valid uses against current uses, checks if too many people have used the voucher.
If (Voucher.CurrentUses >= Voucher.ValidUses) Then
txtVoucher.Text = "Sorry, Voucher is no longer valid"
Else 'Redirects to one of three methods based on discount type.
c.VoucherName = Voucher.VoucherName
If c.discounted = True Then
For Each item As RepeaterItem In rptCart.Items
Dim quantity As TextBox = CType(item.FindControl("txtQuantity"), TextBox)
Dim ProductID As HyperLink = CType(item.FindControl("hlProductID"), HyperLink)
Dim lblPrice As Label = CType(item.FindControl("lblPrice"), Label)
lblPrice.Text = Product.GetProductPrice(ProductID.Text, quantity.Text, c)
Next
End If
Select Case Voucher.DiscountType
Case "Dollar"
txtVoucher.Text = "$ Not yet Supported"
Case "Percentage"
percentageDiscount()
Case "Freebie"
txtVoucher.Text = "Freebie Not Yet Supported"
Case Else
txtVoucher.Text = "Not working."
End Select
End If
End If
Else
End If
End Sub
The two relevant columns are compared in the middle of this function, but my code doesn't execute that far if they are equal to being with. I get the conversion error referencing the line in my CheckForVoucher function that I pasted above. It can't be my comparison that causes the error because the DataTable I use for that doesn't fully exist at the point the error occurs.
The problem you have is when the value of search is 25 characters or longer, you are passing it into the database to compare with the vID column. That column is a uniqueidentifier which means it's a GUID in C# terms. If the value you pass in cannot be converted directly to a GUID, then you will get a conversion error.

Storing reader item in array

Dim myReader As OleDbDataReader
Dim Index As Integer
Dim status As Array
Index = 0
cmd.CommandText = "SELECT CPALLOCATIONTIME from RECORDMASTER where ID='" & TxtID.Text & "'"
cmd.CommandType = CommandType.Text
myReader = cmd.ExecuteReader()
Do While myReader.Read()
status(Index) = myReader.Item(0)
Index = Index + 1
Loop
myReader.Close()
If (Index = 2) Then
If ((status(0) = "Fp" Or status(0) = "Op") And status(1) = "OXp") Then
qText = TxtSTS.Text + "X"
Update = True
ApplicationStatus = 2
ElseIf ((status(0) = "Fp" Or status(0) = "Op") And status(1) = "FXp") Then
qText = TxtSTS.Text + "X"
Update = True
ApplicationStatus = 2
End If
Can some one please help me with status(Index) = myReader.Item(0), giving an error with conversion
You want your array to grow as elements are added. That's not what arrays are for. Use a List(Of T) instead. (See the examples on MSDN for the exact syntax.)
Make sure the data read from the reader has the correct data type. You have two ways of doing that:
Cast it (e.g. DirectCast(myReader(0), String)) or
(better) use the reader method that already returns the correct data type, e.g. myReader.GetString(0).
Redim status(0) ' < -- declare like this
Then in Loop
Redim preserve status(index)
status(Index) = myReader("Column_name")
index = index + 1
Try
status(Index) = myReader.Item(0).ToString