Compare Number of Rows affected - asp.net

I'm trying to compare a string (network ID) and using a SQL Like command, return the numbers of rows affected (if the user name was found or not) however in my code I'm always getting " -1 " which i can not find why, the username is correct and found in the SQL table by running a query in SQL Server Mgt.
Try
Dim Con As New SqlConnection
Con.ConnectionString = "Data Source=WCRDUSMJEMPR9\SQLEXPRESS;Initial Catalog=MicroDB;Integrated Security=True"
Con.Open()
Dim SQL2 As String
SQL2 = "SELECT * from MicroDB_Users WHERE Users LIKE '+#Usercheck+'"
Dim cmd2 As New SqlCommand(SQL2, Con)
cmd2.Parameters.AddWithValue("#Usercheck", TextBox1.Text)
Dim obj2 = cmd2.ExecuteNonQuery
Con.Close()
If obj2 > 0 Then
MsgBox(obj2)
Response.Redirect("~\ControlCharts\AddData_Control.aspx")
Label7_Control.Visible = False
Else
MsgBox(obj2)
Label7_Control.Text = ("You are not authorized to Add Data")
Label7_Control.Visible = True
End If
Catch ex As Exception
MsgBox(Err.Description)
As you can see, i;m using a IF to compare if the user was found ( 1 row affected) or if it was not found ( 0 rows affected).

ExecuteNonQuery is used for insert,update or delete queries only. So you either have to use COUNT in your query and use ExecuteScalar or use ExecuteReader and the reader's HasRows property.
Using var reader = cmd2.ExecuteReader()
If reader.HasRows Then
' ...
Else
' ...
End If
End Using
ExecuteNonQuery:
For UPDATE, INSERT, and DELETE statements, the return value is the
number of rows affected by the command. When a trigger exists on a
table being inserted or updated, the return value includes the number
of rows affected by both the insert or update operation and the number
of rows affected by the trigger or triggers. For all other types of
statements, the return value is -1. If a rollback occurs, the return
value is also -1.
Update: Apart from that you're using the LIKE operator and the parameter incorrectly. Instead of
SQL2 = "SELECT * from MicroDB_Users WHERE Users LIKE '+#Usercheck+'"
cmd2.Parameters.AddWithValue("#Usercheck", TextBox1.Text)
use this approach
SQL2 = "SELECT * from MicroDB_Users WHERE Users LIKE #Usercheck"
cmd2.Parameters.AddWithValue("#Usercheck", string.Format("%{0}%", TextBox1.Text))

The number of rows affected is only returned when you do INSERT, DELETE, and UPDATE.
ExecuteNonQuery
For UPDATE, INSERT, and DELETE statements, the return value is the
number of rows affected by the command. When a trigger exists on a
table being inserted or updated, the return value includes the number
of rows affected by both the insert or update operation and the number
of rows affected by the trigger or triggers. For all other types of
statements, the return value is -1. If a rollback occurs, the return
value is also -1.
To get the number of rows, use SELECT count(*) FROM myTable
ExecuteNonQuery is meant for query that does not return rows, obvious from its name NonQuery.
For query that returns result, use these instead
ExecuteReader() - when multiple rows are returned
ExecuteScalar() - when one row and one column is returned. This will be perfect in your case

The number of rows is affected when you write INSERT UPDATE and DELETE scripts, not SELECT .. Use SQL2 = "SELECT * from MicroDB_Users WHERE Users LIKE '+#Usercheck+'" instead and cmd2.ExecuteScalar()
SQL2 = "SELECT COUNT(*) from MicroDB_Users WHERE Users LIKE '%" + TextBox1.Text + "%'";
Dim cmd2 As New SqlCommand(SQL2, Con)
cmd2.Parameters.AddWithValue("#Usercheck", TextBox1.Text)
Dim obj2 As Int32 = 0
obj2 = Convert.ToInt32(cmd2.ExecuteScalar())

Related

Retrieve the Id of recently inserted record

I currently have this SQL insert code in code behind
Dim con As New SqlConnection
Dim conString As String
conString = ConfigurationManager.ConnectionStrings("MyConnection").ConnectionString
con = New SqlConnection(conString)
con.Open()
Dim cmd As New SqlCommand("INSERT INTO AdditionalDaysRequest(Status, AdditionalDays, Justification,RequestDaySubmitted) VALUES (#Status,#AdditionalDays,#Justification,#RequestDaySubmitted)", con)
cmd.Parameters.AddWithValue("#Status", "Pending Request")
cmd.Parameters.AddWithValue("#AdditionalDays", TB_Days.Text)
cmd.Parameters.AddWithValue("#Justification", TB_Justification.Text)
cmd.Parameters.AddWithValue("#RequestDaySubmitted", Date.Now)
cmd.ExecuteNonQuery()
con.Close()
The Id in this table is automatically generated and incremented
What I would like to have now is the Id of this record inserted to add it to another table
Change your query text to add a second statement:
...;SELECT SCOPE_IDENTITY();
The SELECT SCOPE_IDENTITY() statement Returns the last identity value inserted into an identity column in the same scope as from the MSDN article above.
In addition, you can use the ability of the Sql engine to understand and process two or more command statements passed as a single string if you separe the statements with a semicolon.
In this way you have the great benefit to execute a single trip to the database.
Dim cmd As New SqlCommand("INSERT INTO AdditionalDaysRequest(Status, " & _
"AdditionalDays, Justification,RequestDaySubmitted) VALUES " & _
"(#Status,#AdditionalDays,#Justification,#RequestDaySubmitted);" & _
"SELECT SCOPE_IDENTITY()", con)
cmd.Parameters.AddWithValue("#Status", "Pending Request")
cmd.Parameters.AddWithValue("#AdditionalDays", TB_Days.Text)
cmd.Parameters.AddWithValue("#Justification", TB_Justification.Text)
cmd.Parameters.AddWithValue("#RequestDaySubmitted", Date.Now)
Dim result = cmd.ExecuteScalar()
con.Close()
if result IsNot Nothing Then
Dim lastInsertId = Convert.ToInt32(result)
End If
Notice that the two statements are now executed using ExecuteScalar instead of ExecuteNonQuery because we want to catch the result of the last command.
You will want to run a new SqlCommand. Set the value of lastInsertId with this statement:
SELECT SCOPE_IDENTITY()
This would be an additional knowledge.
we have multiple options like:
##IDENTITY
SCOPE_IDENTITY
IDENT_CURRENT
All three functions return last-generated identity values. However
IDENT_CURRENT returns the last identity value generated for a specific table in any session and any scope.
##IDENTITY returns the last identity value generated for any table in the current session, across all scopes.
SCOPE_IDENTITY returns the last identity value generated for any table in the current session and the current scope.

SQL parameters asp.net(vb.net)

Sorry for my bad English.I have a problem in my code:
Dim sq As String = "SELECT username FROM standing WHERE username = #user"
Dim con As New SqlConnection(Sql.ConnectionString)
Dim cmd As New SqlCommand(sq, con)
cmd.Parameters.Add("#user", SqlDbType.VarChar)
cmd.Parameters("#user").Value = "contesttest"
con.Open()
Dim index As Integer = cmd.ExecuteNonQuery
con.Close()
If (index > 0) Then
'Something..
Else
'Something else..
End If
in my code,"contesttest" is exists in Database and returnedrows(index) should be greater than 0.But index is -1 !What's the problem?
my connectionstring is right.
It does not matter if C# or VB.Net
If your username field is an unique index (meaning that you don't have two username with the same value) then your query could be rewritten without using a SqlDataReader
Dim sq As String = "SELECT username FROM standing WHERE username = #user"
Using con SqlConnection(Sql.ConnectionString)
Using cmd As New SqlCommand(sq, con)
cmd.Parameters.Add("#user", SqlDbType.VarChar)
cmd.Parameters("#user").Value = "contesttest"
con.Open()
Dim username = cmd.ExecuteScalar
If userName IsNot Nothing Then
'Something..
Else
'Something else..
End If
End Using
End Using
ExecuteScalar return the first column of the first row retrieved by your command. In the case you column is a unique index/primary key then you have just one row and you return just the username. So if there is something returned then you have found your user
From MSDN;
For UPDATE, INSERT, and DELETE statements, the return value is the
number of rows affected by the command. When a trigger exists on a
table being inserted or updated, the return value includes the number
of rows affected by both the insert or update operation and the number
of rows affected by the trigger or triggers. For all other types of
statements, the return value is -1. If a rollback occurs, the return
value is also -1.
This is not a problem. It is a definition of ExecuteNonQuery method.
Use a Reader of some sort (like a SqlDataReader) to get the number of rows returned from a SELECT statement or ExecuteScalar to get a single returned value. Using ExecuteNonQuery will only return the number of rows affected when used with a SELECT statement.
For UPDATE, INSERT, and DELETE statements, the return value is the
number of rows affected by the command. When a trigger exists on a
table being inserted or updated, the return value includes the number
of rows affected by both the insert or update operation and the number
of rows affected by the trigger or triggers. For all other types of
statements, the return value is -1. If a rollback occurs, the return
value is also -1.
Read about it on MSDN.
i guess SqlDbType.VarChar will allow only one character ..you need to pass length also for varchar.
for Example:-
cmd.Parameters.Add("#user", SqlDbType.VarChar,80)

SQL - INSERT with Scope_Identity() - getting the record id

I have an ASP.NET page written in VB.NET that gets the items into a GridView by using a SELECT statement with INNER JOIN and also allows you to add an item to the invoice.
INNER JOIN that gets data from items and project_items.
SELECT Items.item_id, Items.item_name, Items.item_cost, project_items.item_quantity
FROM Items
INNER JOIN project_items
ON items.item_id = project_items.item_id
WHERE project_items.project_id = #parameter
#parameter is Session("ProjectID")
(There is a foreign key project_items.item_id -> items.item_id.)
I have an trying to use an SQL statement in VB.NET to try and INSERT into two tables simultaneously. What I tried is I tried to get the item_id of the last record created and insert into another table (project_items) by using that data. However, data is only being entered into the first table.
Any idea what I can do?
This is the code:
Protected Sub btnAddItem_Click(sender As Object, e As EventArgs) Handles btnAddItem.Click
Dim conn As New SqlConnection("Data Source=BRIAN-PC\SQLEXPRESS;Initial Catalog=master_db;Integrated Security=True")
Dim addItemComm As String = "SELECT item_id FROM project_items WHERE project_id=#ProjectID"
Dim user_id_select As New Integer
Dim addItemSQL As New SqlCommand
conn.Open()
addItemSQL = New SqlCommand(addItemComm, conn)
addItemSQL.Parameters.AddWithValue("#ProjectID", Convert.ToInt32(Session("ProjectID")))
Dim datareader As SqlDataReader = addItemSQL.ExecuteReader()
datareader.Close()
conn.Close()
Dim AddNewItemComm As String = "INSERT INTO Items (item_name, item_cost, item_code) VALUES (#ItemName, #ItemCost, #ItemCode); SELECT SCOPE_IDENTITY()"
Dim AddNewItem2Comm As String = "INSERT INTO project_items (item_id, project_id, item_quantity) VALUES (#ItemID, #ProjectID, #ItemQuantity) "
Dim AddNewItemSQL As New SqlCommand
conn.Open()
AddNewItemSQL = New SqlCommand(AddNewItemComm, conn)
AddNewItemSQL.Parameters.AddWithValue("#ItemName", txtItemName.Text.Trim)
AddNewItemSQL.Parameters.AddWithValue("#ItemCost", Convert.ToInt32(txtItemCost.Text))
AddNewItemSQL.Parameters.AddWithValue("#ItemCode", txtItemCost.Text.ToString.ToUpper)
Dim ItemId As Integer
ItemId = AddNewItemSQL.ExecuteScalar()
AddNewItemSQL.ExecuteNonQuery()
conn.Close()
conn.Open()
AddNewItemSQL = New SqlCommand(AddNewItem2Comm, conn)
AddNewItemSQL.Parameters.AddWithValue("#ItemID", ItemId)
AddNewItemSQL.Parameters.AddWithValue("#ProjectID", Convert.ToInt32(Session("ProjectID")))
AddNewItemSQL.Parameters.AddWithValue("#ItemQuantity", Convert.ToInt32(txtItemQuantity.Text))
AddNewItemSQL.ExecuteNonQuery()
conn.Close()
End Sub
Why are you doing this in multiple statements in the first place? Why not:
INSERT dbo.Items (item_name, item_cost, item_code)
OUTPUT inserted.ItemID, #ProjectID, #ItemQuantity
INTO dbo.project_items(item_id, project_id, item_quantity)
VALUES (#ItemName, #ItemCost, #ItemCode);
Now you only have to call one ExecuteNonQuery() and your app doesn't have to care about the actually SCOPE_IDENTITY() value generated. (You can still retrieve SCOPE_IDENTITY() if you want, of course, using ExecuteScalar - but as Nenad rightly points out, pick one instead of calling both.)
Since we now know that there is an explicit foreign key here, we can still reduce your C# code to one call even if we can't use the OUTPUT clause.
DECLARE #i INT;
INSERT dbo.Items (item_name, item_cost, item_code)
SELECT #ItemName, #ItemCost, #ItemCode;
SELECT #i = SCOPE_IDENTITY();
INSERT dbo.project_items(item_id, project_id, item_quantity)
SELECT #i, #ProjectID, #ItemQuantity
SELECT #i; -- if necessary
Would be even cleaner to put this into a stored procedure.
ItemId = AddNewItemSQL.ExecuteScalar()
AddNewItemSQL.ExecuteNonQuery()
These two rows next to each other will execute the command twice. You should remove the second one - ExecuteNonQuery. This will have your data inserted twice in the Items - two same rows but with different IDs.
Since you only retrieve ItemID from the first row, that one should be inserted in project_items, but the other one that was last inserted in items will have no matching row.
Also - complete section from beginning of button click method up before Dim AddNewItemComm As String - where you open and close DataReader and do nothing with it seems completely unnecessary.

checking for duplicate values before attempting insert (ASP.NET)

I have a form where two fields on the first page of the form make up the primary key. I want to check for duplicate values before attempting to insert the record, since I don't want the user to go all the way through the form only to find out they can't submit it. So I'm trying to check for duplicate values when the user tries to go to the next page of the form. I wasn't quite sure how to do it, and sure enough I'm getting an error. ("Object reference not set to an instance of an object.") The problem is apparently in my if statement, "If myValue.Length > 0 Then", but I'm not sure what needs to be in place of that.
Protected Sub CustomValidator1_ServerValidate(ByVal source As Object, ByVal args As System.Web.UI.WebControls.ServerValidateEventArgs) Handles CustomValidator1.ServerValidate
'get values
Dim checkPrefix = txtCoursePrefix.Text
Dim checkNum = txtCourseNum.Text
'db connectivity
Dim myConn As New OleDbConnection
myConn.ConnectionString = AccessDataSource1.ConnectionString
myConn.Open()
'select records
Dim mySelect As New OleDbCommand("SELECT prefix, course_number FROM tableCourse WHERE prefix='checkPrefix' AND course_number='checkNum'", myConn)
'execute(Command)
Dim myValue As String = mySelect.ExecuteScalar()
'check if record exists
If myValue.Length > 0 Then
CustomValidator1.ErrorMessage = "some exp text"
CustomValidator1.SetFocusOnError = "true"
CustomValidator1.IsValid = "false"
End If
End Sub
Thought I'd post the final solution:
'select records
Dim mySelect As New OleDbCommand("SELECT 1 FROM tableCourse WHERE prefix=? AND course_number=?", myConn)
mySelect.Parameters.AddWithValue("#checkPrefix", checkPrefix)
mySelect.Parameters.AddWithValue("#checkNum", checkNum)
'execute(Command)
Dim myValue = mySelect.ExecuteScalar()
'check if record exists
If myValue IsNot Nothing Then
CustomValidator1.SetFocusOnError = True
args.IsValid = False
End If
This error indicates that the content of myValue variable is null. If it's null you can't use Length property (or any other property for that matter) on it. You have to check for null explicitly:
If myValue IsNot Nothing Then
EDIT 1
Your sql query is wrong. I don't know what would be the right query, as I don't know your database, but I think you intender to write this:
Dim mySelect As New OleDbCommand("SELECT prefix, course_number FROM tableCourse WHERE prefix=" + checfkPreix + " AND course_number=" + checkNum, myConn)
or something to that effect. You might want to consider using string.Format function for forming the string. And you also need to make sure that there is some kind of protection against SQL Injection, since you form your query from user input. In your case using of OleDbParameter might be appropriate.
Edit 2
You also right to mention that there might be a problem with ExecuteScalar. ExecuteScalar is supposed to return a single value and your select query are returning two (prefix and course_number). Change it so that it returns a single parameter SELECT prefix FROM or simply SELECT 1 FROM and then the rest of the query:
Dim mySelect As New OleDbCommand("SELECT 1 FROM tableCourse WHERE prefix=? AND course_number=?", myConn)
mySelect.Parameters.AddWithValue("#checkPrefix", checkPrefix)
mySelect.Parameters.AddWithValue("#checkNum", checkNum)
Edit 3
You are not setting failed validation properly in your validator.
Add
args.IsValid = False
inside your if statement.
First ExecuteScalar will only return a single value, so in this case you are only going to get the column prefix from the result. Second if there is no match with your query it will return null, so your next length check should account for that scenario:
if String.IsNullOrEmpty(myValue) Then
...
Reference: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalar.aspx
myValue is null if there is no duplicate, so you have to apply .Length only if myValue is not null (which means checking for null only is enough; without .Length)
If Not string.IsNullOrEmpty(myValue) Then
try something like this instead (you will have to adapt it to VB.Net) DBNull is different from Null or Nothing so you have to compare it to both
If myValue <> DBNull and not myvalue is nothing Then

Executenonquery return value

I want to perform a search on a table to see if record exists. I do not want to perform insert or update after. I have done this already but somehow I cannot get this to work. On my asp.net page I cannot seem to get any value returned. The error is "input string not in correct format" I ma sure it is obvious but I cannot seem to see it now!
here is my code:
Dim con As New SqlConnection("connstring")
Dim cmd As New SqlCommand("checkname", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add(New SqlParameter("#d", SqlDbType.Int))
cmd.Parameters("#id").Value = TextBox1.Text
Dim para As New SqlParameter
para.Direction = ParameterDirection.ReturnValue
para.ParameterName = "returnvalue"
cmd.Parameters.Add(para)
con.Open()
cmd.ExecuteNonQuery()
Dim exists As Integer
exists = Convert.ToInt32(cmd.Parameters("returnvalue").Value)
If exists = 1 Then
Label1.Text = "You......"
ElseIf exists = 0 Then
Label1.Text = "You....."
End If
con.Close()
stored procedure:
CREATE PROCEDURE checkname
-- Add the parameters for the stored procedure here
#id int
AS
--This means it exists, return it to ASP and tell us
-- SELECT 'already exists'
IF EXISTS(SELECT * FROM attendees WHERE id = #id)
BEGIN
RETURN 1
END
ELSE
BEGIN
RETURN 0
END
You need to ensure that you are passing an integer.
int intValue;
if(!int.TryParse(TextBox1.Text, out intValue))
{
// Update your page to indicate an error
return;
}
cmd.Parameters.Add(New SqlParameter("id", SqlDbType.Int));
cmd.Parameters("id").Value = intValue;
(Technically you don't need the "#" character when
defining the parameters in the .NET
code.)
You have declared your procedure parameter as #d instead of #id. Also a return parameter cannot be an input parameter. The return value should be an exit code. You most likely want to create an output parameter and set that to 1 or zero inside of your stored procedure.
Edit: to clarify, the return value is generally regarded as an indicator of correct execution. Zero usually means success, where any other numeric value is generally regarded as an error code. That is why I recommended adding an output parameter instead of adding a return value parameter.
ExecuteNonQuery returns the number of rows affected. Therefore the return values that you set in your stored procedure are thrown away and will not be returned by the ExecuteNonQuery method.
ExecuteNonQuery is used to Insert / Delete / Update operations. Not for SELECT, you need either ExecuteScalar or ExecuteReader methods. This link will help you to know how to use output parameters : http://aspdotnet-suresh.blogspot.com/2010/10/introduction-here-i-will-explain-how-to.html

Resources