I'm trying to search a sql table for a specific string, and return the number of observations found. It keeps returning -1 though, whether the string is in the table or not. Here's my code:
#{
Layout = "~/_Layout.cshtml";
Page.title = "TestArea";
var db = Database.Open("Cafeen");
string SearchWord = "Jolly";
var msg = db.Execute("SELECT COUNT(*) FROM Products WHERE ProductName = #SearchWord");
}
<p>#msg</p>
Should I perhaps use something other than COUNT(*)? What is the significance of -1? I would have assumed the expression to return 0 if the string can't be found.
You are using the WebMatrix.Data namespace. In this context you should call the QuerySingle method not the Execute one because, as many have already stated, that method is for not returning rows data.
The Execute method is used to perform non-query commands on a
database, such as the SQL Drop, Create, Delete, Update, and Insert
commands.
Moreover I suggest to change your query statement to a more performant one
var db = Database.Open("Cafeen");
string SearchWord = "Jolly";
string cmdText = #"IF EXISTS(SELECT 1 FROM Products
WHERE ProductName = #searchWord)
SELECT 1 ELSE SELECT 0";
int exists = Convert.ToInt32(db.QuerySingle(cmdText, SearchWord));
.....
Pertinent to the SQL Database, there is:
SqlCommand.ExecuteScalar Method ()
(re: https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalar(v=vs.110).aspx)
Otherwise, refer to Database.QueryValue Method (re: https://msdn.microsoft.com/en-us/library/webmatrix.data.database.queryvalue(v=vs.111).aspx)
Both methods return a scalar value from the first column/ first row.
Also, instead of COUNT(*) in SQL statement you can use COUNT(1) for better performance.
Hope this may help.
In db.Execute and SqlCommand.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 like SELECT, the return value is -1. If a rollback occurs, the return value is also -1.
Have a look at the following links may be helpful:
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executenonquery.aspx
How to Identify whether SQL job is successfully executed or not in C#
Related
Good morning everyone,
The short and sweet question is: what will SqlCommand.ExecuteNonQuery() return in the case of the query being multiple drop table statements?
For example, if I pass five tables to my drop method, and it builds a query with five drop table statements, what will ExecuteNonQuery return? I think it will return a value of negative one (based on MSDN), hoping it will return the exact count of tables that were dropped successfully, and hoping that it will not return the number of rows cumulatively removed from the database since this would be extremely excessive and most likely not the answer.
CODE
string query = string.Empty;
foreach (string name in tableNames)
query += $"DROP TABLE [{name}]; ";
using (SqlCommand cmd = new SqlCommand(query, conn)
droppedTableCount = cmd.ExecuteNonQuery(); // Returns number of rows affected.
return droppedTableCount;
MSDN
You can use the ExecuteNonQuery to perform catalog operations (for example, querying the structure of a database or creating database objects such as tables), or to change the data in a database without using a DataSet by executing UPDATE, INSERT, or DELETE statements. Although the ExecuteNonQuery 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. 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.
We are refactoring a project from plain MySQL queries to the usage of NHibernate.
In the MySQL connector there is the ExecuteNonQuery function that returns the rows affected. So
int RowsDeleted = ExecuteNonQuery("DELETE FROM `table` WHERE ...");
would show me how many rows where effectively deleted.
How can I achieve the same with NHibernate? So far I can see it is not possible with Session.Delete(query);.
My current workaround is first loading all of the objects that are about to be deleted and delete them one-by-one, incrementing a counter on each delete. But that will cost performance I may assume.
If you don't mind that nHibernate will create delete statements for each row and maybe additional statements for orphans and/or other relationships, you can use session.Delete.
For better performance I would recommend to do batch deletes (see example below).
session.Delete
If you delete many objects with session.Delete, nHibernate makes sure that the integrity is preserved, it will load everything into the session if needed anyways. So there is no real reason to count your objects or have a method to retrieve the number of objects which have been deleted, because you would simply do a query before running the delete to determine the number of objects which will be affected...
The following statement will delete all entities of type post by id.
The select statement will query the database only for the Ids so it is actually very performant...
var idList = session.Query<Post>().Select(p => p.Id).ToList<int>();
session.Delete(string.Format("from Post where Id in ({0})", string.Join(",", idList.ToArray())));
The number of objects deleted will be equal to the number of Ids in the list...
This is actually the same (in terms of queries nHibernate will fire against your database) as if you would query<T> and loop over the result and delete all of them one by one...
Batch delete
You can use session.CreateSqlQuery to run native SQL commands. It also allows you to have input and output parameters.
The following statement would simply delete everything from the table as you would expect
session.CreateSQLQuery(#"Delete from MyTableName");
To retrieve the number of rows delete, we'll use the normal TSQL ##ROWCOUNT variable and output it via select. To retrieve the selected row count, we have to add an output parameter to the created query via AddScalar and UniqueResult simple returns the integer:
var rowsAffected = session.CreateSQLQuery(#"
Delete from MyTableName;
Select ##ROWCOUNT as NumberOfRows")
.AddScalar("NumberOfRows", NHibernateUtil.Int32)
.UniqueResult();
To pass input variables you can do this with .SetParameter(<name>,<value>)
var rowsAffected = session.CreateSQLQuery(#"
DELETE from MyTableName where ColumnName = :val;
select ##ROWCOUNT NumberOfRows;")
.AddScalar("NumberOfRows", NHibernateUtil.Int32)
.SetParameter("val", 1)
.UniqueResult();
I'm not so confortable with MySQL, the example I wrote is for MSSQL, I think in MySQL the ##ROWCOUNT equivalent would be SELECT ROW_COUNT();?
Im using Data Adapter/Set in SQL CE, i do create the following query to insert into table and then SELECT ##IDENTITY,
I want this SELECT statement return me the Student ID each time after Inserting into table, here is my Query:
INSERT INTO [Student] ([Name], [Family], [Address], [Phonenumber])
VALUES(#Name,#Family,#Address,#Phonenumber);
SELECT ##IDENTITY;
here is how i call query:
int x = da.Insert("Albert", "Alexandra", "No4.Oxford", Telnum);
Int x suppose to return me ID...
Here is the Error im getting :
There was an error parsing the query. [ Token line number = 4,Token line offset = 1,Token in error = SELECT ]
Insert Query it self it works but once adding SELECT ## IDENTITY at the end im getting error.
I really don't know what i'm doing wrong.
The return value of ExecuteNonQuery will be number of rows effected by these query. so you need to use store procedure instead of Single Query.
According to MSDN, CE doesn't support multiple commands per execution and you need to do this as two commands synchronously.
If you'd like to do this in a single call, you need to use a stored procedure rather than Insert, because it uses ExecuteNonQuery, which does not return any records. Otherwise you'll need to perform a select in another call to determine the identity.
The return value of ExecuteNonQuery is an integer that denotes the number of rows affected by your call.
This is my (rough) code (DAL):
int i;
// Some other declarations
SqlCommand myCmdObject = new SqlCommand("some query");
conn.open();
i = myCmdObject.ExecuteNonQuery();
conn.close();
The problem is: Even though there is a record present on my SELECT query, the value in i remains -1.
What could be the problem?
What kind of query do you perform? Using ExecuteNonQuery is intended for UPDATE, INSERT and DELETE queries. As per the documentation:
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.
Whenever you want to execute an SQL statement that shouldn't return a value or a record set, the ExecuteNonQuery should be used.
So if you want to run an update, delete, or insert statement, you should use the ExecuteNonQuery. ExecuteNonQuery returns the number of rows affected by the statement. This sounds very nice, but whenever you use the SQL Server 2005 IDE or Visual Studio to create a stored procedure it adds a small line that ruins everything.
That line is: SET NOCOUNT ON; This line turns on the NOCOUNT feature of SQL Server, which "Stops the message indicating the number of rows affected by a Transact-SQL statement from being returned as part of the results" and therefore it makes the stored procedure always to return -1 when called from the application (in my case a web application).
In conclusion, remove that line from your stored procedure, and you will now get a value indicating the number of rows affected by the statement.
Happy programming!
http://aspsoft.blogs.com/jonas/2006/10/executenonquery.html
You use EXECUTENONQUERY() for INSERT,UPDATE and DELETE.
But for SELECT you must use EXECUTEREADER().........
Because the SET NOCOUNT option is set to on. Remove the line "SET NOCOUNT ON;" in your query or stored procedure.
See more at SqlCommand.ExecuteNonQuery() returns -1 when doing Insert / Update / Delete.
Could you post the exact query? The ExecuteNonQuery method returns the ##ROWCOUNT Sql Server variable what ever it is after the last query has executed is what the ExecuteNonQuery method returns.
The ExecuteNonQuery method is used for SQL statements that are not queries, such as INSERT, UPDATE, ... You want to use ExecuteScalar or ExecuteReader if you expect your statement to return results (i.e. a query).
From MSDN: SqlCommand.ExecuteNonQuery Method
You can use the ExecuteNonQuery to
perform catalog operations (for
example, querying the structure of a
database or creating database objects
such as tables), or to change the data
in a database without using a DataSet
by executing UPDATE, INSERT, or DELETE
statements.
Although the ExecuteNonQuery 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. 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.
You are using SELECT query, thus you get -1
If what you want is to get just a single integer from the query, use:
myCmdObject.ExecuteScalar()
if you want to run an update, delete,
or insert statement, you should use
the ExecuteNonQuery. ExecuteNonQuery
returns the number of rows affected by
the statement.
How to Set Count On
how do you check for no rows returned after ExecuteNonQuery for SELECT sql statement returns no rows??
The ExecuteNonQuery Method returns the number of row(s) affected by either an INSERT, an UPDATE or a DELETE. This method is to be used to perform DML (data manipulation language) statements as stated previously.
The ExecuteReader Method will return the result set of a SELECT. This method is to be used when you're querying for a bunch of results, such as rows from a table, view, whatever.
The ExecuteScalar Method will return a single value in the first row, first column from a SELECT statement. This method is to be used when you expect only one value from the query to be returned.
In short, that is normal that you have no results from a SELECT statement while using the ExecuteNonQuery method. Use ExecuteReader instead. Using the ExecuteReader method, will will get to know how many rows were returned through the instance of the SqlDataReader object returned.
int rows = 0;
if (reader.HasRows)
while (reader.Read())
rows++;
return rows; // Returns the number of rows read from the reader.
I don't see any way to do this. Use ExecuteScalar with select count(*) where... to count the rows that match the criteria for your original SELECT query. Example below, paraphrased from here:
using (SqlCommand thisCommand =
new SqlCommand("SELECT COUNT(*) FROM Employee", thisConnection))
{
Console.WriteLine("Number of Employees is: {0}",
thisCommand.ExecuteScalar());
}
If you need the rows as well, you would already be using ExecuteReader, I imagine.
Use the ExecuteReader method instead. This returns a SqlDataReader, which has a HasRows property.
ExecuteNonQuery shouldn't be used for SELECT statements.
This is late, but I ran into this problem recently and thought it would be helpful for others coming in later (like me) seeking help with the same problem. Anyway, I believe you actually could use the ExecuteNonQuery they way you are trying to. BUT... you have to adjust your underlying SELECT query to a stored procedure instead that has SELECT query and an output parameter which is set to equal the row count.
As stated in the MSDN documentation:
Although the ExecuteNonQuery returns no rows, any output parameters or return values mapped to parameters are populated with data.
Given that, here's how I did it. By the way, I would love feedback from the experts out there if there are any flaws in this, but it seems to work for me.
First, your stored procedure should have two SELECT statements: one to return your dataset and another tied to an output parameter to return the record count:
CREATE PROCEDURE spMyStoredProcedure
(
#TotalRows int output
)
AS
BEGIN
SELECT * FROM MyTable; //see extra note about this line below.
SELECT #TotalRows COUNT(*) FROM MyTable;
END
Second, add this code (in vb.net, using SqlCommand etc..).
Dim cn As SqlConnection, cm As SqlCommand, dr As SqlDataReader
Dim myCount As Int32
cn = New SqlConnection("MyConnectionString")
cn.Open() //I open my connection beforehand, but a lot of people open it right before executing the queries. Not sure if it matters.
cm = New SqlCommand("spMyStoredProcedure", cn)
cm.CommandType = CommandType.StoredProcedure
cm.Parameters.Add("#TotalRows", SqlDbType.Int).Direction = ParameterDirection.Output
cm.ExecuteNonQuery()
myCount = CType(cm.Parameters("#TotalRows").Value, Integer)
If myCount > 0 Then
//Do something.
End If
dr = cm.ExecuteReader()
If dr.HasRows Then
//Return the actual query results using the stored procedure's 1st SELECT statement
End If
dr.Close()
cn.Close()
dr = Nothing
cm = Nothing
cn = Nothing
That's it.
Extra note. I assumed you may have wanted to get the "MyCount" amount to do something other than determining whether to continue returning you're query. The reason is because with this method, you don't really need to do that. Since I'm utilizing the "ExecuteReader" method after getting the count, I can determine whether to continue returning intended data set using the data reader's "HasRows" property. To return a data set, however, you need a SELECT statement which returns a data set, hence the reason for my 1st SELECT statement in my stored procedure.
By the way, the cool thing about this method of using the "ExecuteNonQuery" method is you can use it to get the total row count before closing the DataReader (you cannot read output parameters before closing the DataReader, which is what I was trying to do, this method gets around that). I'm not sure if there is a performance hit or a flaw in doing this to get around that issue, but like I said... it works for me. =D