I've been experimenting with what I can do with a database, but I'm unfamiliar with aspects like storing a query result in a variable. I've used this snippet to query my database with more than one record, but the result I keep getting is zero. Can someone explain how this works? Here's my snippet...
str = "SELECT COUNT(Nickname) FROM Backup"
cmd.CommandText = str
cmd.Connection = myConn
myConn.Open()
cntPlns = cmd.ExecuteNonQuery()
MessageBox.Show(cntPlns.ToString)
The connection is there, but my result always comes out zero...thanks for any suggestions.
See ExecuteNonQuery doesn't return results for ...nonquery is the wrong cmd.
Try this>>
str = "SELECT COUNT(Nickname) as myCount FROM Backup"
cmd.CommandText = str
cmd.Connection = myConn
myConn.Open()
Using cntPlns As SqlDataReader = command.ExecuteReader
If cntPlns.Read Then
MessageBox.Show(cntPlns.GetInt32(0).ToString) ' the first column
End If
End Using
You should be calling ExecuteScalar, not ExecuteNonQuery. ExecuteNonQuery is for executing a non-query, i.e. a SQL statement that does not produce a result set. ExecuteScalar is for executing a query and retrieving a scalar, i.e. a single value, which comes from the first column of the first row of the result set, whether or not that result set contains more data.
For the record, you get zero every time because ExecuteNonQuery returns the number of rows affected by the SQL statement, where affected means changed. A SELECT statement affects no rows so zero is the correct result.
It might serve you well to check out my ADO.NET examples to see what objects and members to use where and when.
Related
I am working in Classic ASP. I know there is a record that matches my simple SQL select query. It has the ' character ' in it. The code is as follows:
Fieldname = Replace(trim(Request.form("Fieldname")),"'","'", 1, 10)
'replace the "'" up to 10 times with the ' code to avoid SQL issues, LOL.
SQL = "select id,fieldname from table where fieldname='"&Trim(Fieldname)&"'"
set rs = server.createobject("adodb.recordset")
rs.open SQL, Application("conn"), 1, 1
If not rs.eof then
response.redirect "somepage.asp?QS=Fieldname_Exists_in_DB"
Else
'Sample.hold the value in a hidden input field and pass it to the next page
End If
The problem is, I know for a fact the fieldname and fieldname value is in the MS-SQL 2016 server table. I pull data from it all the time. The value in the database field contains the ' value as does the Replaced FORM Fieldname when it is compared to the SQL database field, so it should NOT pass the IF NOT RS.EOF question. Yet it passes every time.
What am I missing? I'm doing the exact same query in other places on this exact same app and it behaves as one would expect.
Tried to explain in the comments but as the point is being missed, I'll try to give you an example here.
Do not trust user input
Classic ASP server-side code that interacts with the ADODB Library doesn't have any notion of sanitised data. This means that any input that comes from the user via the Request object (like Request.Form("Fieldname")) should not be trusted.
Fieldname = Replace(trim(Request.form("Fieldname")),"'","'", 1, 10)
SQL = "select id,fieldname from table where fieldname='"&Trim(Fieldname)&"'"
This example is open to SQL Injection attacks and is generally bad practise and leads to security flaws that can be easily exploited with script tools readily available on the internet.
Manually sanitising data
Apart from the security flaws introduced, it also makes it harder to query data due to how SQL calls for strings and other data types need to be constructed (which varies from provider to provider). Having to account for the various combinations of characters that could be deemed dangerous or likely to break the query can be a cumbersome task and one seen far too often in the wild when ADODB already has a solution.
Parameterised Queries
The ADODB Library has an in-built object called ADODB.Command which takes all these hassles away.
Using the example in the question the same query can be written without the failings of manually sanitising data or executing SQL directly against user input.
Const adCmdText = 1
Const adVarWChar = 202
Const adParamInput = 1
Dim Fieldname, SQL, cmd, rs,
Fieldname = Trim(Request.Form("Fieldname") & "")
SQL = "SELECT id, fieldname FROM table WHERE fieldname = ?"
Set cmd = Server.CreateObject("ADODB.Command")
With cmd
.ActiveConnection = Application("conn")
.CommandType = adCmdText 'Also can use 1
.CommandText = SQL
Call .Append(.CreateParameter("#fieldName", adVarWChar, adParamInput, 255))
Set rs = .Execute(, Array(Fieldname))
End With
Set cmd = Nothing
If Not rs.EOF then
response.redirect "somepage.asp?QS=Fieldname_Exists_in_DB"
Else
'Sample.hold the value in a hidden input field and pass it to the next page
End If
Useful Links
A: Using METADATA to Import DLL Constants (shows an approach to using Named Constants that doesn't require adding your own Const declarations to the code).
I have some general purpose code in my app for calling non-query commands like inserts:
DBComm.CommandText = SQL
DBComm.Connection = Cnn
Ans = DBComm.ExecuteNonQuery
I'm using this to call an SP that takes two strings and returns an int:
Dim SQL As String = "EXEC Import_Validation " & Code & "," & User
Return DbS.Execute(SQL)
This works fine, with the exception that the return value is not the value of the SP (is it a job id of some sort?). So I modified it slightly:
Param = New SqlParameter("#RETURN_VALUE", SqlDbType.Int)
Param.Direction = ParameterDirection.ReturnValue
DBComm.Parameters.Add(Param)
DBComm.CommandText = SQL
DBComm.Connection = Cnn
DBComm.ExecuteNonQuery
This runs, but always returns 0 for RETURN_VALUE. I suspect this is because I do not have the following line:
DBComm.CommandType = CommandType.StoredProcedure
Is that suspicion correct?
However, if I add this line, the SQL no longer works, complaining Could not find stored procedure "Import_Validation '1234', 'maury'. I assume that is because it thinks the string I passed in is just the name, and is being confused by the parameters. I could add the parameters as input parameters on DBComm, but then the method would be specific to a particular SP.
So is there a way I can call an SP using SQL I construct and still get a parameter back out?
If you are just returning an integer, I've used this:
Param.value=cmd.ExecuteScalar()
I Cannot guess nor explain why you had trouble executing the store procedure, since you didn't share the full code (full part of the code that have issue). However, generally speaking, when you use ExecuteNonQuery() you're supposed to use a valid T-SQL. By default, the commandType is Text. So, if you need to execute a store procedure, you'll need to change the command type to StoredProcedure before executing the query. So, I would say your guess is correct in this line :
DBComm.CommandType = CommandType.StoredProcedure
Also, in your code, you declared a #RETURN_VALUE parameter, but I couldn't see anything calling its value !? So, maybe this is the issue ?
anyhow, check this :
Using connection As New SqlConnection(ConnectionString)
command As New SqlCommand("dbo.Import_Validation", connection)
command.CommandType = CommandType.StoredProcedure
command.Parameters.Add("#Code", SqlDbType.VarChar, 250)
command.Parameters.Add("#User", SqlDbType.VarChar, 250)
command.Parameters.Add("#RETURN_VALUE", SqlDbType.Int).Direction = ParameterDirection.ReturnValue
command.Parameters("#Code").Value = Code
command.Parameters("#User").Value = User
connection.Open()
command.ExecuteNonQuery()
'IF returned value is more than one row, then use reader instead
Dim return_value As Integer = Convert.ToInt32(command.Parameters("#RETURN_VALUE").Value)
connection.Close()
End Using
I got an SQL 2005 table with many (84 to be specific) fields (actually it is a query returned by a procedure)
It looks like when I access recordset fields placed later then some field placed earlier becomes empty while server had actually returned a value for it
Had anyone such problem?
My solution is to put such disappeared field at the end of a table so when it is accessed later by a code (here VBA) its value is still accessible BUT I see it as a big problem in ADODB.Recordset 2.8 as I should not care about field order
I know that question is not very specific but maybe someone had a similar issue?
One way to to make sure the field values are there is to pass on the recordset to a array like (You will have to build your own connection function):
Function getStoredProcedure() As Variant
Dim rs As ADODB.Recordset
Dim cmd As ADODB.Command
Dim conn As ADODB.Connection
Dim values As Variant
Set conn = getConn("Server", "Database")
Set cmd = New ADODB.Command
cmd.ActiveConnection = conn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "StoredProcedureName"
cmd.Parameters.Item("#TODAY") = today
Set rs = cmd.Execute
If Not rs.EOF Then
values = rs.GetRows
Else
Exit Function
End If
Set cmd = Nothing
getStoredProcedure= transposeArray(values)
End Function
From there you can always retrieve the values from the array. Otherwise, without seeing your code or understand what you are trying to do, I cannot tell if this is really an issue with ADODB because I cannot recreate this issue when pulling field items in any order I want such as: rs.Fields.Item(i).Value for i = any number in any order.
I met this problem twice. There are two exception fields in my query string. Running the query string in sql server, they can return the values but these two exception fields are empty when run the query string in VBA used recordset. I put these exception fields behind other normal fields in the query string, and then they can return value in the recordset instead of blank. So it's really a big problem.
Basically I'm retrieving all the data in my program through runtime, I was wondering how will I retrieve the number of rows affected after an update so I could prompt the user about it through VB.NET
What I'm actually doing is, after an update, if there are no other rows updated then the user can no longer click on the button
By using ExecuteNonQuery, it will returns no rows, any output parameters or return values mapped to parameters are populated with data.
For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command.
EDIT:
You can prompt the User like
Dim RowsAffected as Integer = Command.ExecuteNonQuery()
MsgBox("The no.of rows effected by update query are " & RowsAffected.ToString)
If you're using the SQLCommand object directly then a call to ExecuteNonQuery will return a count of rows affected:
Dim I as Integer= MyCommandObject.ExecuteNonQuery()
Hope this makes sense.
You can use SqlCommand for this:
Dim cmd As SqlCommand
Dim rows_Affected as Integer
rows_Affected = cmd.ExecuteNonQuery()
You can update your statements to return the rowcount value.
This should be helpful http://technet.microsoft.com/en-us/library/ms187316.aspx
I am currently writing a VB .NET application where I am trying to open 1 database, create a select statement and then post the results into another database file using Microsoft Access database 2003.
The code seems to stop executing at the statement cmdJetDB.ExecuteNonQuery()
I am using the following code:
Dim conn1 As OleDbConnection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data source=C:\Sample.mdb")
Dim conn2 As OleDbConnection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data source=C:\db2.mdb")
conn1.Open()
conn2.Open()
Dim mySelectQuery As String
mySelectQuery = "SELECT Sample.LANE_ADDR, Sample.LANE_DT, Sample.LANE_TM, Sample.LANE_SPEED FROM (Sample) WHERE ((Sample.LANE_ADDR) = '164.909' OR (Sample.LANE_ADDR) = '164.909' AND Sample.LANE_DT BETWEEN #4/4/2003# AND #4/5/2003#)"
Dim cmdJetDB As New OleDbCommand(mySelectQuery, conn1)
cmdJetDB.ExecuteNonQuery()
Dim cmdInsert As String
cmdInsert = "Insert INTO Table1 (Sample.LANE_ADDR, Sample.LANE_TM,Sample.LANE_SPEED) VALUES ('164.909', '00:12:30' , '30' )"
Dim cmdJetDB2 As New OleDbCommand(cmdInsert, conn2)
cmdJetDB2.ExecuteNonQuery()
conn2.Close()
conn1.Close()
Question: What is it that I am not doing. I opened both connections, stated my two SQL statements, yet it is still not working. I really need to get this application working. Please Help.........
ExecuteNonQuery cannot be used to SELECT stuff from a database. You should use ExecuteReader and use the result in a loop to set the parameters of the INSERT statement and then run ExecuteNonQuery in that loop. From the code you've written, how you'd expect the values should be populated in the INSERT statement?
Here is a sugestion,
If the columns you are retriving have the same type as the columns you are inserting (Basicaly you are not making any conversion and/or transformations) do a single query that does this.
INSERT INTO TestTable2
SELECT * FROM TestTable1
You're using SELECT to try to return rows, but then calling ExecuteNonQuery(), which returns nothing. You'll want to use ExecuteReader() instead.
You'll probably get another error later because you're INSERTing into "Table1" but trying to reference fields in "Sample".
Also unrelated to the error, but you aren't doing anything with the data in the SELECT statement to use it in the INSERT statement.