Data Mismatch Error in VB.net SQL statement - sql

I have this code:
Protected Sub unlikebtn_Click(sender As Object, e As EventArgs) Handles unlikebtn.Click
Dim strSQL As String
Dim MemberDataConn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; data source=" & Server.MapPath("database/Database.mdb"))
Dim MemberCommand As New OleDbCommand(strSQL, MemberDataConn)
MemberDataConn.Open()
MemberCommand.Connection = MemberDataConn
MemberCommand.CommandText = "DELETE FROM LIKES WHERE user_id ='" & Session("user_id") & "' AND post_id = '" & Session("post_id") & "'"
MemberCommand.ExecuteNonQuery()
MemberDataConn.Close()
likebtn.Visible = True
unlikebtn.Visible = False
End Sub
When I run it, I get an error on the .ExecuteNonQuery():
System.Data.OleDb.OleDbException: 'Data type mismatch in criteria expression.
I don't think the problem is the data-types in the database...

It is (almost) always a bad idea to concatenate values into an SQL command. Instead, you should use SQL parameters to pass the values.
Also, instances of some classes, such as an OleDbConnection, use unmanaged resources and you have to tell the .NET Framework to dispose of those resources when you've finished using them. You can either call the .Dispose() method yourself or use the Using construct. The latter is tidier as it will take care of the disposal even if there was a problem.
So your code could look like:
Dim strSQL As String = "DELETE FROM LIKES WHERE user_id = ? AND post_id = ?"
Using conn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; data source=" & Server.MapPath("database/Database.mdb"))
Using sqlCmd As New OleDbCommand(strSQL, conn)
'TODO: set the OleDbType to match the columns in the database '
sqlCmd.Parameters.Add(New OleDbParameter With {
.ParameterName = "#UserId",
.OleDbType = OleDbType.VarWChar,
.Size = 32,
.Value = CStr(Session("user_id"))})
sqlCmd.Parameters.Add(New OleDbParameter With {
.ParameterName = "#PostId",
.OleDbType = OleDbType.Integer,
.Value = CInt(Session("post_id"))})
conn.Open()
sqlCmd.ExecuteNonQuery()
conn.Close()
End Using
End Using
likebtn.Visible = True
unlikebtn.Visible = False
The ?s in the SQL command are placeholders for the parameters. The parameter names aren't used, but it makes it easier to see what is what in the code. Because the names aren't used, the parameters must be added in the same order as the corresponding placeholders. You will need to adjust the types of the parameters (and the sizes for strings) to match the column types in the database.
Incidentally, if the site is to run under IIS, then you could put the database in the App_Data directory as nothing in there will be served to a client, by default. Also, SQL Server is a more suitable database for a multi-user environment - you can use the Express edition for free.

Related

Incorrect syntax near 'NO'.' in vb.net on cmd.ExecuteNonQuery()

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If con.State = ConnectionState.Open Then
con.Close()
End If
con.Open()
cmd = con.CreateCommand()
cmd.CommandType = CommandType.Text
cmd.CommandText = "update Tabledb set FIRSTNAME=" & TextBox1.Text & ",LASTNAME=" & TextBox2.Text & ",PHONE NO=" & TextBox3.Text & ", where Id =" & i & ""
cmd.ExecuteNonQuery()
cmd.Connection = con
disp_data()
End Sub
Give you controls meaningful names. This will make your coding much easier. I have renamed your controls as an example.
You should not have to check ConnectionState. Connections, commands and other database objects use unmanaged resources. To release these they provide a Dispose method which must be called. These objects should be declared locally in the method where they are used. vb.net provides Using...End Using blocks where you declare connections, commands etc. The block will dispose the objects at the End Using. (It will also Close the connection which you failed to do.)
Don't Open the connection until directly before the .Execute....
You can pass the the connection string directly to the connection's constructor. Your can pass the CommandText and the Connection directly to the constructor of the command.
It is useless to set the Connection property of the command after you have attempted to execute the command.
CommandType.Text is the default so it is not necessary to set this property explicitly.
NEVER concatenate strings to build Sql statements.
ALWAYS use parameters.
The field names you use in you Sql string must match exactly the names in the database. That means upper case, lower case, spaces, and periods. If a field name is a reserved word, contains a space or other unusual character is needs to be surrounded by identifier delimiters. For Access and Sql Server that would be brackets [ ]. For MySql use the back tick `. On my USA keyboard that is found below the tilde in the upper left corner. If you are not sure if you need the delimiters you can use them anyway. It won't hurt anything.
I had to guess at the datatypes of the parameters. Check the database for the actual types. I also guessed at the database. Change the code to OleDb for Access and MySql for MySql.
Private OPConStr As String = "Your connection string."
Private Sub btnUpdate_Click(sender As Object, e As EventArgs) Handles btnUpdate.Click
Dim i As Integer = 5 'I made up a value, don't know where this comes from in the real code
Dim strSql = "update Tabledb set FIRSTNAME = #FirstName, LASTNAME = #LastName, [PHONENO.] = #Phone, where Id = #ID;"
Using con As New SqlConnection(OPConStr),
cmd As New SqlCommand(strSql, con)
cmd.Parameters.Add("#FirstName", SqlDbType.NVarChar).Value = txtFirstName.Text
cmd.Parameters.Add("#LastName", SqlDbType.NVarChar).Value = txtLastName.Text
cmd.Parameters.Add("#Phone", SqlDbType.VarChar).Value = txtPhone.Text
cmd.Parameters.Add("#ID", SqlDbType.Int).Value = i
con.Open()
cmd.ExecuteNonQuery()
End Using
disp_data()
End Sub

No value given for one or more required parameters error vb.net

no_hp = TextBox1.Text
alamat = TextBox2.Text
password = TextBox3.Text
cmd = New OleDbCommand("UPDATE [user] SET no_hp = '" & CInt(TextBox1.Text) & "',alamat = " & TextBox2.Text & ", pin ='" & CInt(TextBox3.Text) & "' WHERE id = " & id & "", conn)
cmd.Connection = conn
cmd.ExecuteReader()
i was trying to update my access database with the following error
i cant seem to see where i did wrong
i already changed the data type from the textbox to match with the data types used in the database
the no_hp and pin is integer so i converted it to Cint but it doesnt seem to work
i already tried to substitute it to a variable but still it didnt work
please tell me where i did wrong
Use Parameters to avoid SQL injection, a malious attack that can mean data loss. The parameter names in Access do not matter. It is the order that they are added which must match the order in the SQL statement that matters.
The Using...End Using statements ensure that you objects are closed and disposed even it there is an error. This is most important for connections.
You con't need to set the connection property of the command because you passed the connection in the constructor of the command.
ExcuteReader is for retrieving data. Use ExecuteNonQuery to update, insert of delete.
Private Sub UpdateUsers()
Using conn As New OleDbConnection("Your connection string")
Using cmd = New OleDbCommand("UPDATE [user] SET no_hp = ?,alamat = ?, pin =? WHERE id = ?", conn)
cmd.Parameters.Add("nohp", OleDbType.Integer).Value = CInt(TextBox1.Text)
cmd.Parameters.Add("alamat", OleDbType.VarChar).Value = TextBox2.Text
cmd.Parameters.Add("pword", OleDbType.Integer).Value = CInt(TextBox3.Text)
cmd.Parameters.Add("id", OleDbType.Integer).Value = id
conn.Open()
cmd.ExecuteNonQuery()
End Using
End Using
End Sub

Adodb Recordset function .MoveNext Causes Exception "UPDATE permission was denied"

I've run into a problem today that has stumped me.
Here is some sample code:
Dim objRec As ADODB.Recordset
Dim oRec As ADODB.Recordset
Dim oRecBuild As New ADODB.Recordset
cmd = New ADODB.Command()
cmd.ActiveConnection = objConn
cmd.CommandText = "SelectAll_PhoneNumbers_ById"
cmd.CommandType = ADODB.CommandTypeEnum.adCmdStoredProc
cmd.NamedParameters = True
cmd.Parameters.Append(cmd.CreateParameter("#ObjId", ADODB.DataTypeEnum.adVarChar, ADODB.ParameterDirectionEnum.adParamInput, 20, objRec.Fields("PK_ProgramID").Value))
oRec = New ADODB.Recordset()
oRec.Open(cmd, , ADODB.CursorTypeEnum.adOpenStatic, ADODB.LockTypeEnum.adLockOptimistic)
If oRec.EOF = False Then
Do Until oRec.EOF
If IsDBNull(oRec.Fields("PhoneType").Value) = False Then
sName = PhoneNumberEdit(oRec.Fields("Phone").Value)
If IsDBNull(oRec.Fields("Extension").Value) = False And Len(oRec.Fields("Extension").Value) > 0 Then
sName = PhoneNumberEdit(oRec.Fields("Phone").Value) & " " & oRec.Fields("Extension").Value
End If
oRecBuild.AddNew(New Object() {"TextPrint", "TextType"}, New Object() {sName, oRec.Fields("PhoneType")})
End If
oRec.MoveNext()
Loop
End If
When I reach the .MoveNext() function the app throws an error that reads like this: The UPDATE permission was denied on the object 'PhoneNumbers', database 'MyDb', schema 'dbo'.
Nothing in this code block is calling an update (the function calls in the loop are just formatting data), does anyone have any idea of what could be causing this?
I should also add that I can run this using SSPI locally, however the code needs to be able to run on a server using a SQL username and PW; I have tested updates with the app on other pages, and it works fine.
This is just a hunch, but I do see one place in that code that might result in an UPDATE commend: oRecBuild.AddNew(). I don't see how it could, but I wonder if calling oRec.MoveNext() is somehow forcing a commit from oRecBuild. Otherwise, I'd take a longer look at the SelectAll_PhoneNumbers_ById procedure, and any possible triggers that might be attached to tables or views it uses.
And if that fails, I'd do this:
Public Class PhoneNumber
Public Number As String
Public PhoneType As String
End Public
'...
Dim result As New List(Of PhoneNumber)
Using cn As New SqlConnection("connection string"), _
cmd As New SqlCommand("SelectAll_PhoneNumbers_ById", cn)
cmd.CommandType = CommandType.StoredProcedure
'Is this really an integer?
cmd.Parameters.Add("#ObjId", SqlDbType.NVarChar, 20).Value = objRec.Fields("PK_ProgramID").Value
cn.Open()
Using rdr As SqlDataReader = cmd.ExecuteReader()
While rdr.Read()
Dim phone As String = ""
If Not IsDbNull(rdr("PhoneType"))
phone = PhoneNumberEdit(rdr("Phone"))
End If
If Not IsDbNull(rdr("Extension"))
phone = phone & " " & PhoneNumberEdit(rdr("Extension"))
End If
result.Add(New PhoneNumber With {.Number = phone, .PhoneType = rdr("PhoneType")})
End While
End Using
End Using
While I'm at it... anytime you're reading data from one recordset into another there's a very strong chance that the whole thing could be done entirely in the database, with no client code at all.
To close this question, I wanted to go ahead and say that I finally was able to get this resolved. The issue was that dynamic sql being executed with sp_executesql explicitly checks the select, insert, or update privileges of the SQL user; execute privs are NOT enough.
So, either the dynamic SQL has to be done away with or the select/update/insert/delete privs must be granted.
Thank you all for the help and time.

How do I assign the results of an SQL query to multiple variables in VB.NET?

This is my first attempt at writing a program that accesses a database from scratch, rather than simply modifying my company's existing programs. It's also my first time using VB.Net 2010, as our other programs are written in VB6 and VB.NET 2003. We're using SQL Server 2000 but should be upgrading to 2008 soon, if that's relevant.
I can successfully connect to the database and pull data via query and assign, for instance, the results to a combobox, such as here:
Private Sub PopulateCustomers()
Dim conn As New SqlConnection()
Dim SQLQuery As New SqlCommand
Dim daCustomers As New SqlDataAdapter
Dim dsCustomers As New DataSet
conn = GetConnect()
Try
SQLQuery = conn.CreateCommand
SQLQuery.CommandText = "SELECT Customer_Name, Customer_ID FROM Customer_Information ORDER BY Customer_Name"
daCustomers.SelectCommand = SQLQuery
daCustomers.Fill(dsCustomers, "Customer_Information")
With cboCustomer
.DataSource = dsCustomers.Tables("Customer_Information")
.DisplayMember = "Customer_Name"
.ValueMember = "Customer_ID"
.SelectedIndex = -1
End With
Catch ex As Exception
MsgBox("Error: " & ex.Source & ": " & ex.Message, MsgBoxStyle.OkOnly, "Connection Error !!")
End Try
conn.Close()
End Sub
I also have no problem executing a query that pulls a single field and assigns it to a variable using ExecuteScalar. What I haven't managed to figure out how to do (and can't seem to hit upon the right combination of search terms to find it elsewhere) is how to execute a query that will return a single row and then set various fields within that row to individual variables.
In case it's relevant, here is the GetConnect function referenced in the above code:
Public Function GetConnect()
conn = New SqlConnection("Data Source=<SERVERNAME>;Initial Catalog=<DBNAME>;User Id=" & Username & ";Password=" & Password & ";")
Return conn
End Function
How do I execute a query so as to assign each field of the returned row to individual variables?
You probably want to take a look at the SqlDataReader:
Using con As SqlConnection = GetConnect()
con.Open()
Using cmd As New SqlCommand("Stored Procedure Name", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add("#param", SqlDbType.Int)
cmd.Parameters("#param").Value = id
' Use result to build up collection
Using dr As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection Or CommandBehavior.SingleResult Or CommandBehavior.SingleRow)
If (dr.Read()) Then
' dr then has indexed columns for each column returned for the row
End If
End Using
End Using
End Using
Like #Roland Shaw, I'd go down the datareader route but an other way.
would be to loop through
dsCustomers.Tables("Customer_Information").Rows
Don't forget to check to see if there are any rows in there.
Google VB.Net and DataRow for more info.

Inserting variables into a query string - it won't work!

Basically i have a query string that when i hardcode in the catalogue value its fine. when I try adding it via a variable it just doesn't pick it up.
This works:
Dim WaspConnection As New SqlConnection("Data Source=JURA;Initial Catalog=WaspTrackAsset_NROI;User id=" & ConfigurationManager.AppSettings("WASPDBUserName") & ";Password='" & ConfigurationManager.AppSettings("WASPDBPassword").ToString & "';")
This doesn't:
Public Sub GetWASPAcr()
connection.Open()
Dim dt As New DataTable()
Dim username As String = HttpContext.Current.User.Identity.Name
Dim sqlCmd As New SqlCommand("SELECT WASPDatabase FROM dbo.aspnet_Users WHERE UserName = '" & username & "'", connection)
Dim sqlDa As New SqlDataAdapter(sqlCmd)
sqlDa.Fill(dt)
If dt.Rows.Count > 0 Then
For i As Integer = 0 To dt.Rows.Count - 1
If dt.Rows(i)("WASPDatabase") Is DBNull.Value Then
WASP = ""
Else
WASP = "WaspTrackAsset_" + dt.Rows(i)("WASPDatabase")
End If
Next
End If
connection.Close()
End Sub
Dim WaspConnection As New SqlConnection("Data Source=JURA;Initial Catalog=" & WASP & ";User id=" & ConfigurationManager.AppSettings("WASPDBUserName") & ";Password='" & ConfigurationManager.AppSettings("WASPDBPassword").ToString & "';")
When I debug the catalog is empty in the query string but the WASP variable holds the value "WaspTrackAsset_NROI"
Any idea's why?
Cheers,
jonesy
alt text http://www.freeimagehosting.net/uploads/ba8edc26a1.png
I can see a few problems.
You are using concatenation in a SQL statement. This is a bad practice. Use a parameterized query instead.
You are surrounding the password with single quotes. They are not needed and in fact, I'm surprised it even works assuming the password itself does not have single quotes.
You should surround classes that implement IDisposable with a Using block
You should recreate the WASP connection object in GetWASPcr like so:
Public Sub GetWASPAcr()
Dim username As String = HttpContext.Current.User.Identity.Name
Dim listOfDatabaseConnectionString As String = "..."
Using listOfDatabaseConnection As SqlConnection( listOfDatabaseConnectionString )
Using cmd As New SqlCommand("SELECT WASPDatabase FROM dbo.aspnet_Users WHERE UserName = #Username")
cmd.Parameters.AddWithValue( "#Username", username )
Dim dt As New DataTable()
Using da As New SqlDataAdapter( cmd )
da.Fill( dt )
If dt.Rows.Count = 0 Then
WaspConnection = Null
Else
Dim connString As String = String.Format("Data Source=JURA;Initial Catalog={0};User Id={1};Password={2};" _
, dt.Rows(0)("WASPDatabase") _
, ConfigurationManager.AppSettings("WASPDBUserName") _
, ConfigurationManager.AppSettings("WASPDBPassword"))
WaspConnection = New SqlConnection(connString);
End If
End Using
End Using
End Using
End Sub
In this example, listOfDatabaseConnectionString is the initial connection string to the central database where it can find the catalog name that should be used for subsequent connections.
All that said, why would you need a class level variable to hold a connection? You should make all your database calls open a connection, do a sql statement, close the connection. So, five database calls would open and close a connection five times. This sounds expensive except that .NET gives you connection pooling so when you finish with a connection and another is requested to be opened, it will pull it from the pool.
Your string passed into the constructor for this SqlConnection object will be evaluated when the class is instantiated. Your WASP variable (I'm assuming) won't be set until the method you have shown is called.
Might want to quit looking one you have found your database:
For i As Integer = 0 To dt.Rows.Count - 1
If dt.Rows(i)("WASPDatabase") Is DBNull.Value Then
WASP = ""
Else
WASP = "WaspTrackAsset_" + dt.Rows(i)("WASPDatabase")
break
End If
Next
[link text][1]You are building your string on the fly by adding the value of a column to a string. So, for the row in question for the column "WASPDatabase" was tacked on to your string. So you got what it had. On another note, your earlier query of "select ... from ... where ..." where you are manually concatinating the string of a variable makes you WIDE OPEN to SQL-Injection attacks.
Although this link [1]: how to update a table using oledb parameters? "Sample query using parameterization" is to a C# sample of querying with parameterized values, the similar principles apply to most all SQL databases.
At the time you're creating the new connection, WASP is holding the value you want it to be holding? It is a string data type? Try adding .ToString after WASP and see if that helps anything.
Interesting problem. =-)
The problem is, as Paddy already points out, that the WaspConnection object gets initialized before you even have the chance to call GetWASPAcr. Try this:
Public Sub GetWASPAcr()
'[...]
End Sub
Dim _waspConnection As SqlConnection
Public Readonly Property WaspConnection As SqlConnection
Get
If _waspConnection Is Nothing Then
GetWASPAcr()
_waspConnection = New SqlConnection("Data Source=JURA;Initial Catalog=" & WASP & ";User id=" & ConfigurationManager.AppSettings("WASPDBUserName") & ";Password='" & ConfigurationManager.AppSettings("WASPDBPassword").ToString & "';")
End If
Return _waspConnection
End Get
End Property