"Operation must be an updateable query" VB.Net OleDB for Excel - sql

Ive been trying to find a solution for this problem without any success:
I'm using VB.NET and I need to read and update records from an Excel file. I use the OleDB API for that. It works fine for all the reading, but impossible to write to the file (Update or Insert queries)
Here is what I have:
My connection string:
Public connString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\...\Resources\attempt.xls;Extended Properties='Excel 8.0;HDR=YES;IMEX=1;'"
Select query that works fine:
Dim checkQuery = "SELECT * FROM [Sheet1$] WHERE [TravellerPN] = #T"
Try
Using connection As New OleDb.OleDbConnection(Form.connString)
Dim checkCommand As New OleDbCommand(checkQuery, connection)
checkCommand.Parameters.Add("#T", OleDbType.VarChar).Value = PN
connection.Open()
Dim reader As OleDbDataReader = checkCommand.ExecuteReader()
Dim path As String = ""
While reader.Read()
path = reader("Datapath").ToString
End While
reader.Close()
MsgBox(PN & " " & DP & " " & path,,)
If a record for the part number entered doesnt exist, and nothing is returned, insert a new line
If path = "" Then
Dim addQuery = "INSERT INTO [Sheet1$] ([TravellerPN],[Datapath]) VALUES (#T, #D)"
Dim addCommand As New OleDbCommand(addQuery, connection)
addCommand.Parameters.Add("#T", OleDbType.VarChar).Value = PN
addCommand.Parameters.Add("#D", OleDbType.VarChar).Value = DP
Dim rows As Integer = addCommand.ExecuteNonQuery()
And this was where it returns the error.
MsgBox(rows & " row added!",, "") 'Never diplayed
And other query that doesn't work either:
Else 'If does exist, confirm replacement'
Dim replaceResponse = MsgBox("A path already exists for " & PN & "." & vbNewLine & "Do you want to replace " & path & " with " & DP & "?", MsgBoxStyle.YesNo, "Overwrite previous datapath?")
Dim replaceQuery = "UPDATE [Sheet1$] SET [Datapath] = #D WHERE [TravellerPN]=#T"
Dim replaceCommand As New OleDbCommand(replaceQuery, connection)
replaceCommand.Parameters.Add("#D", OleDbType.VarChar).Value = DP
replaceCommand.Parameters.Add("#T", OleDbType.VarChar).Value = PN
Dim rows As Integer = replaceCommand.ExecuteNonQuery()
MsgBox(rows & " row updated!",, "")
End If
connection.Close()
End Using
I've tried to fix the issue: it could be caused by permissions, so I authorized even guests accounts to modify my folder.
If it were a ReadOnly mode in the connection: I tried adding Mode=ReadWrite but my connection String didn't work after that. (That option seems only available for ADO connections?)
I tried running the app as administrator
And finally, I'm posting this here hoping to get some help.
Sorry or the long post, I was trying to give all the elements that could potentially be a problem.
Thanks.

Related

How to quick update MySQL table through a loop using VB.net

My code for updating mysql table having more than 2000 rows through a loop using VB.net is working fine but too slow. Is there any way to update it faster ? Anybody please help. Thanks. My code is given below.
Dim mysqlconn = New MySqlConnection
mysqlconn.ConnectionString = "server=localhost;user id=root;password=1234;database=Share"
mysqlconn.Open()
Dim adapter As New MySqlDataAdapter("SELECT * FROM name_list;", mysqlconn)
Dim datatable As New DataTable()
adapter.Fill(datatable)
Dim cmd As New MySqlCommand
cmd.Connection = mysqlconn
Dim sql As String
Dim i as integer = 0
While i <= datatable.Rows.Count - 1
Dim sy As String = datatable.Rows(i).Item(3).ToString.Trim
sql = "UPDATE Name_list Set Numerology = '" & "N-" & variable1 & " S- " & variable2 & "',FSTLetter = '" & variable3 & "',Timing = '" & vriable4 & "',P_Numerology = '" & variable5 & "' WHERE Symbol = '" & sy & "'"
sy = ""
cmd.CommandText = sql
cmd.ExecuteNonQuery()
i = i + 1
End While
adapter.Fill(datatable)
DataGridView1.DataSource = datatable
DataGridView1.Refresh()
Don't name variables the same as class names (DataTable, datatable) vb.net is case insensitive so it confuses intellisense.
Database connections and commands need to closed and disposed.
Using blocks do this for you even if there is an error.
You can set the connection string by passing it directly to the constructor of the connection. Likewise, you can set the command text and the connection by passing to the constructor of the command.
Don't open the connection until right before it is used. In this case we don't need a DataAdapter but if you are using one it is not necessary to open the connection at all. The .Fill method of the DataAdapter will open and close the connection. However if the DataAdapter finds an open connection it will leave it open.
To avoid confusion, I created 2 data tables. I used a single connection but I opened and closed it each time it is used. It is not disposed until the last End Using.
The first command retrieves only the sy column. Replace Column4_Name with the actual column name. We don't want to pull down data we don't need so no Select *.
Always use parameters to avoid sql injection which can damage your database. You need to check your database for the types of the fields. I had to guess. Each parameters value is set except sy which changes on each iteration.
No need to close the connection after the last Select command since the final End Using will close and dispose.
After the connection is closed we update the user interface.
Private Sub OPCode(variable1 As String, variable2 As String, variable3 As String, variable4 As String, variable5 As String)
Dim dtBeforeUpdate As New DataTable()
Dim dtAfterUpdate As New DataTable()
Using mysqlconn = New MySqlConnection("server=localhost;user id=root;password=1234;database=Share")
Using cmd As New MySqlCommand("SELECT Column4_Name FROM name_list;", mysqlconn)
mysqlconn.Open()
dtBeforeUpdate.Load(cmd.ExecuteReader)
mysqlconn.Close()
End Using
Using cmd As New MySqlCommand($"UPDATE Name_list Set Numerology = #Numerologh, FSTLetter = #FST, Timing = #Timing, P_Numerology = #P_Numerology WHERE Symbol = #sy ", mysqlconn)
cmd.Parameters.Add("#Numerology", MySqlDbType.String).Value = $"N-{variable1} S- {variable2}"
cmd.Parameters.Add("#FST", MySqlDbType.String).Value = variable3
cmd.Parameters.Add("#Timing", MySqlDbType.String).Value = variable4
cmd.Parameters.Add("#P_Numerology", MySqlDbType.String).Value = variable5
cmd.Parameters.Add("#sy", MySqlDbType.String)
mysqlconn.Open()
For Each row As DataRow In dtBeforeUpdate.Rows
cmd.Parameters("#sy").Value = row(0).ToString.Trim
cmd.ExecuteNonQuery()
Next
mysqlconn.Close()
End Using
Using cmd As New MySqlCommand("Select * From Name_list;", mysqlconn)
mysqlconn.Open()
dtAfterUpdate.Load(cmd.ExecuteReader)
End Using
End Using
DataGridView1.DataSource = dtAfterUpdate
End Sub
Actually, I don't get it. It seems like you are updated the entire table with the same data. Do you expect the variable1, variable2 etc. to change somehow?
Don't know where your variable1, variable2, etc come from, but those look to be static, so your loop is somewhat pointless it would seem. You're updating every row in the loop to the exact same values (unless there's other code you're not showing), so just update the table without the loop:
Using con As New MySQLConnection
con.ConnectionString = "server=localhost;user id=root;password=1234;database=Share"
con.Open
Using cmd As New MySQLCommand
cmd.Connection = con
cmd.CommandText = "UPDATE Name_list Set Numerology = '" & "N-" & variable1 & " S- " & variable2 & "',FSTLetter = '" & variable3 & "',Timing = '" & vriable4 & "',P_Numerology = '" & variable5 & "'"
cmd.ExecuteNonQuery
End Using
End Using

MysqlDataReader.Read stuck on the last record and doesnt EOF

i confused why mySqlDataReader.Read stuck on the last record and doesnt EOF ..
Here's my private function for executeSql :
Private Function executeSQL(ByVal str As String, ByVal connString As String, ByVal returnRecordSet As Boolean) As Object
Dim cmd As Object
Dim objConn As Object
Try
If dbType = 2 Then
cmd = New MySqlCommand
objConn = New MySqlConnection(connString)
Else
cmd = New OleDbCommand
objConn = New OleDbConnection(connString)
End If
'If objConn.State = ConnectionState.Open Then objConn.Close()
objConn.Open()
cmd.Connection = objConn
cmd.CommandType = CommandType.Text
cmd.CommandText = str
If returnRecordSet Then
executeSQL = cmd.ExecuteReader()
executeSQL.Read()
Else
cmd.ExecuteNonQuery()
executeSQL = Nothing
End If
Catch ex As Exception
MsgBox(Err.Description & " #ExecuteSQL", MsgBoxStyle.Critical, "ExecuteSQL")
End Try
End Function
And this is my sub to call it where the error occurs :
Using admsDB As MySqlConnection = New MySqlConnection("server=" & rs("server") & ";uid=" & rs("user") & ";password=" & rs("pwd") & ";port=" & rs("port") & ";database=adms_db;")
admsDB.Open()
connDef.Close()
rs.Close()
'get record on admsdb
Dim logDate As DateTime
Dim str As String
str = "select userid, checktime from adms_db.checkinout in_out where userid not in (select userid " &
"from adms_db.checkinout in_out join (select str_to_date(datetime,'%d/%m/%Y %H:%i:%s') tgl, fid from zsoft_bkd_padang.ta_log) ta " &
"on ta.fid=userid and tgl=checktime)"
Dim rsAdms As MySqlDataReader = executeSQL(str, admsDB.ConnectionString, True)
Dim i As Integer
'This is where the error is, datareader stuck on the last record and doesnt EOF
While rsAdms.HasRows
'i = i + 1
logDate = rsAdms(1)
'save to ta_log
str = "insert into ta_log (fid, Tanggal_Log, jam_Log, Datetime) values ('" & rsAdms(0) & "','" & Format(logDate.Date, "dd/MM/yyyy") & "', '" & logDate.ToString("hh:mm:ss") & "', '" & logDate & "')"
executeSQL(str, oConn.ConnectionString, False)
rsAdms.Read()
End While
'del record on admsdb
str = "truncate table checkinout"
executeSQL(str, admsDB.ConnectionString, False)
End Using
i'm new to vbnet and really have a little knowledge about it,, please help me,, and thank you in advance..
The issue is that you're using the HasRows property as your loop termination expression. The value of that property never changes. Either the reader has rows or it doesn't. It's not a check of whether it has rows left to read, so reading has no effect.
You are supposed to use the Read method as your flag. The data reader begins without a row loaded. Each time you call Read, it will load the next row and return True or, if there are no more rows to read, it returns False.
You normally only use HasRows if you want to do something special when the result set is empty, e.g.
If myDataReader.HasRows Then
'...
Else
MessageBox.Show("No matches found")
End If
If you don't want to treat an empty result set as a special case then simply call Read:
While myDataReader.Read()
Dim firstFieldValue = myDataReader(0)
'...
End While
Note that trying to access any data before calling Read will throw an exception.

SQL query is not running IN VB.NET

I am fresher in VB.NET and I am trying to execute an SQL query in VB.NET but not showing any value at output. Can u please help me to find where am I going Wrong.
Dim sConnectionString As String _
= "User ID=XXX ;Password=XXX;Initial Catalog=gemXXX;Data Source=SCRBAMSDKBXXXXXX"
Dim objConn As New SqlConnection(sConnectionString)
objConn.Open()
Dim sw ,readerObj
Dim sSQL As String = "select top 1 " & sw & " = e.import from tblrelcoms r , [beant].[dbo].tblequipments e where r.IDEquipment = e.IDEquipment"
Using readerObj As SqlClient.SqlDataReader = cmdObj.ExecuteReader
Dim objCmd As New SqlCommand(sSQL, objConn)
objCmd.ExecuteNonQuery()
TextBox1.Text = sw.ToString()
The problem you have is that you cannot just concatenate a variable into SQL and expect it to be updated once the SQL is executed.
ExecuteScalar is probably the easiest way of achieving what you want:
Dim sConnectionString As String _
= "User ID=XXX ;Password=XXX;Initial Catalog=gemXXX;Data Source=SCRBAMSDKBXXXXXX"
Dim sSQL as string = "SELECT TOP 1 e.import " _
"FROM tblrelcoms r " & _
" INNER JOIN [beant].[dbo].tblequipments e " & _
" ON r.IDEquipment = e.IDEquipment " & _
"ORDER BY e.Import;"
Using connection = new SqlConnection(sConnectionString)
Using command = New SqlCommand(sSQL, connection)
connection.Open()
TextBox1.Text = command.ExecuteScalar().ToString()
End Using
End Using
Although if you need more than one column, then you could use a data reader:
Dim sConnectionString As String _
= "User ID=XXX ;Password=XXX;Initial Catalog=gemXXX;Data Source=SCRBAMSDKBXXXXXX"
Dim sSQL as string = "SELECT TOP 1 e.import " _
"FROM tblrelcoms r " & _
" INNER JOIN [beant].[dbo].tblequipments e " & _
" ON r.IDEquipment = e.IDEquipment " & _
"ORDER BY e.Import;"
Using connection = new SqlConnection(sConnectionString)
Using command = New SqlCommand(sSQL, connection)
connection.Open()
Using reader = command.ExecuteReader()
If reader.Read()
TextBox1.Text = reader.GetString(0)
End If
End Using
End Using
End Using
I have made a couple of other changes too.
Added Using blocks to ensure IDisposable objects are disposed of properly.
Updated the sql join syntax from ANSI 89 implicit joins to ANSI 92 explicit joins, as the name suggests the syntax you are using is 24 years out of date. There are many reasons to start using the new syntax, which is nicely covered in this article: Bad habits to kick : using old-style JOINs
Added an ORDER BY clause to your sql. TOP 1 without order by will give you indeterminate results (unless you only have one record, in which case top 1 is redundant)
A more complex solution would be to use output parameters, which will work and seems more in line with what you were originally trying to achieve, but is overkill for this situation (in my opinion):
Dim sConnectionString As String _
= "User ID=XXX ;Password=XXX;Initial Catalog=gemXXX;Data Source=SCRBAMSDKBXXXXXX"
Dim sSQL as string = "SELECT TOP 1 #Output = e.import " _
"FROM tblrelcoms r " & _
" INNER JOIN [beant].[dbo].tblequipments e " & _
" ON r.IDEquipment = e.IDEquipment " & _
"ORDER BY e.Import;"
Using connection = new SqlConnection(sConnectionString)
Using command = New SqlCommand(sSQL, connection)
connection.Open()
Dim p As SqlParameter = command.Parameters.Add("#Output", SqlDbType.VarChar, 255)
p.Direction = ParameterDirection.InputOutput
command.ExecuteNonQuery();
TextBox1.Text = p.Value.ToString()
End Using
End Using
*Please excuse any syntax errors, I have not used VB.Net in years, and some c# quirks may be in the below, such as I can't remember if you just don't have to use parentheses for a parameterless method, or if you can't... Hopefully there is enough basic structure to get you started

Visual basic - Incrementing the score

Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim READER As MySqlDataReader
Dim Query As String
Dim connection As MySqlConnection
Dim COMMAND As MySqlCommand
Dim item As Object
Try
item = InputBox("What is the item?", "InputBox Test", "Type the item here.")
If item = "shoe" Then
Dim connStr As String = ""
Dim connection As New MySqlConnection(connStr)
connection.Open()
Query = "select * from table where username= '" & Login.txtusername.Text & " '"
COMMAND = New MySqlCommand(Query, connection)
READER = COMMAND.ExecuteReader
If (READER.Read() = True) Then
Query = "UPDATE table set noOfItems = noOfItems+1, week1 = 'found' where username= '" & Login.txtusername.Text & "'"
Dim noOfItems As Integer
Dim username As String
noOfItems = READER("noOfItems") + 1
username = READER("username")
MessageBox.Show(username & "- The number of items you now have is: " & noOfGeocaches)
End If
Else
MsgBox("Unlucky, Incorrect item. Please see hints. Your score still remains the same")
End If
Catch ex As Exception
MessageBox.Show("Error")
End Try
I finally got the message box to display! but now my code does not increment in the database, can anybody help me please :D
Thanks in advance
After fixing your typos (space after the login textbox and name of the field retrieved) you are still missing to execute the sql text that updates the database.
Your code could be simplified understanding that an UPDATE query has no effect if the WHERE condition doesn't find anything to update. Moreover keeping an MySqlDataReader open while you try to execute a MySqlCommand will trigger an error in MySql NET connector. (Not possible to use a connection in use by a datareader). We could try to execute both statements in a single call to ExecuteReader separating each command with a semicolon and, of course, using a parameter and not a string concatenation
' Prepare the string for both commands to execute
Query = "UPDATE table set noOfItems = noOfItems+1, " & _
"week1 = 'found' where username= #name; " & _
"SELECT noOfItems FROM table WHERE username = #name"
' You already know the username, don't you?
Dim username = Login.txtusername.Text
' Create the connection and the command inside a using block to
' facilitate closing and disposing of these objects.. exceptions included
Using connection = New MySqlConnection(connStr)
Using COMMAND = New MySqlCommand(Query, connection)
connection.Open()
' Set the parameter value required by both commands.
COMMAND.Parameters.Add("#name", MySqlDbType.VarChar).Value = username
' Again create the reader in a using block
Using READER = COMMAND.ExecuteReader
If READER.Read() Then
Dim noOfItems As Integer
noOfItems = READER("noOfItems")
MessageBox.Show(username & "- The number of items you now have is: " & noOfItems )
End If
End Using
End Using
End Using

Using results of a SqlDataReader in a SQL query

I would like to get the results of my reader to be able to be used in a WHERE clause in another SQL command. I have tried to put the reader into a variable to use but it does not work. I've never used readers before so I do not know how they work. Can anyone give me an idea of how to get the result of the reader into there where statement? Thanks.
The code:
Dim courseSelectCom = New SqlCommand("select stuff((select ','+course_name from course where school= '" & schoolSelect & "' for xml path ('')), 1, 1, '')", connection)
Dim reader = courseSelectCom.ExecuteReader()
If reader.Read() Then
Dim courseVar As String
courseVar = "%" & reader("course_name") & "%"
Using totalStudentCom = New SqlCommand("SELECT COUNT(student_ID) FROM student " & "course_name like #course", connection)
totalStudentCom.Parameters.AddWithValue("#course", courseVar)
Dim result = totalStudentCom.ExecuteScalar()
MessageBox.Show("Students for course = " & result.ToString)
End Using
End If
There are a couple of problems here.
First you should use parametrized query and not string concatenations for building sql commands
Second when a DataReader is opened, the connection object cannot serve another command unless you have specified the substring MultipleActiveResultSets=True; in your connection string
Dim courseSelectCom = New SqlCommand("select course_name from course where school= #school", connection)
courseSelectCom.Parameters.AddWithValue("#school", schoolSelect)
Dim reader = courseSelectCom.ExecuteReader()
if reader.Read() then
Dim courseVar As String
courseVar = "%" & reader("course_name") & "%"
Using totalStudentCom = new SqlCommand("SELECT COUNT(student_ID) FROM student " & _
"course_name like #course", connection)
totalStudentCom.Parameters.AddWithValue("#course", courseVar)
Dim result = totalStudentCom.ExecuteScalar()
MessageBox.Show("Students for course = " & result.ToString)
End Using
End If
Remember that this works only if MARS is enabled