Why this query returning -1? - c#

I'm trying to get the max id of the table category using this code
string maxid = "";
string query = "SELECT MAX(Cat_ID) + 1 FROM Category";
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["JokerCafe"].ConnectionString);
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(query, conn);
maxid = cmd.ExecuteNonQuery().ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
conn.Close();
}
return maxid;
I run this query in sql it is returning exact value but when try to execute it from code it returns -1. Kindly guide me what's going wrong with it?

ExecuteNonQuery() will return the affected row count. For example if you are trying to execute any update statement or delete statement through ExecuteNonQuery() method then it will return the number of affected rows.
But, if you want to fetch a value from specific field then you need to try ExecuteScalar() method. It will return Object type value. Using this method you can fetch only a single value record.
object val = command.ExecuteScalar();
if (val != null)
{
//Do your stuff here.
}

ExecuteScaler is your solution
It executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored.
so do modify your code to
maxid = cmd.ExecuteScalar().ToString();
or
maxid = cmd.ExecuteScalar() as string; //to be safe side if return value is null
and you'll get the value expected from the query

Related

ExecuteScalar() always return NULL

I am trying to return an integer from the database using ExecuteScalar(). However, when I run the query on the database itself, I get the correct answer, and c# gives me a 0 (Null) all the time. I know it returns a null because before i added id = Convert.ToInt32(command.ExecuteScalar()); it would give me an error telling me to make sure NULL is handled. I am expecting it to return a 3 btw.
private int getFamilyId()
{
int id = 0;
using (SqlConnection connection = new SqlConnection(Globaldata.ConnectionString))
{
using (SqlCommand command = new SqlCommand())
{
string sqlString = #"SELECT [Id] FROM [dbo].[FamilyDetails];";
command.Connection = connection;
command.CommandText = sqlString;
try
{
connection.Open();
id = Convert.ToInt32(command.ExecuteScalar());
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK);
}
finally
{
connection.Close();
}
return id;
}
}
}
When you do this:
string sqlString = #"SELECT [Id] FROM [dbo].[FamilyDetails];";
You don't want to do this:
id = Convert.ToInt32(command.ExecuteScalar());
Three things could go wrong here.
Problem #1:
If there are no rows in the table, command.ExecuteScalar() wil return Null.
Problem #2:
If there are any rows in the table, command.ExecuteScalar() wil return the value of the first rows it happens to encounter because the SELECT statement is not restricted to 1 value.
Problem #3:
If the Id column is not declared as NOT NULL command.ExecuteScalar() could return a DbNull, which which makes no sense when converted to an Integer.
Try and see what happens when there are 0 or 1 or 2 records in the table.
--UPDATE--
It works now, My connection string had one character missing. I think it happened when I took out the connection Timeout part of the connection string.
Thank you for your suggestions!!!

ExecuteNonQuery returning -1 when using sql COUNT despite the query string

For some reason, ExecuteNonQuery() in C# returns -1, though when I run a query separately, the value returns the actual value needed.
For Example:
try
{
var connString ="Data Source=ServerName;InitialCatalog=DatabaseName;Integrated Security=true;"
SqlConnection conn = new SqlConnection(connString);
SqlCommand someCmd = new SqlCommand("SELECT COUNT(*) FROM SomeTable");
someCmd.Connection = conn;
conn.Open();
var theCount = cmd.ExecuteNonQuery();
conn.Close();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
When the command is executed it returns -1. Though if run the query separately,
SELECT COUNT(*) FROM SomeTable;
Column returns one row with a count of 4 if that table being queried has 4 rows.
Based on 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.
You want to return the number of rows affected by the command and save it to an int variable but since the type of statement is select so it returns -1.
Solution: If you want to get the number of rows affected by the SELECT command and save it to an int variable you can use ExecuteScalar.
var theCount = (int)cmd.ExecuteScalar();
You can use Ef core with Ado.net like this example
var context = new SampleDbContext();
using (var connection = context.Database.GetDbConnection())
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = "SELECT COUNT(*) FROM SomeTable";
var result = command.ExecuteScalar().ToString();
}
}

Saving a result from stored procedure in code behind

I want to retrieve a project id from my project table in SQL Server.
I created a stored procedure like this:
create proc spFindProjectID
(#customerid int)
as
begin
select Project.pID
from Project
where Project.cID=#customerid
end
Now in my C# I execute that proc like this:
public int findid(int id)
{
con = connect("igroup9_test1ConnectionString");
using (SqlCommand sqlComm = new SqlCommand("[spFindProjectID]", con))
{
if (con.State != ConnectionState.Open)
{
con.Open();
}
try
{
sqlComm.CommandType = CommandType.StoredProcedure;
sqlComm.Parameters.AddWithValue("#customerid", id);
sqlComm.CommandTimeout = 600;
sqlComm.ExecuteNonQuery();
}
catch (Exception ex)
{
throw (ex);
}
return
}
}
I want to save the result from the procedure and return it.
How can I do this?
Let's have a look at the documentation for ExecuteNonQuery:
For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command. ... For all other types of statements, the return value is -1.
You're calling a stored procedure, which is none of the 3 listed statements.
I assume your
select Project.pID
from Project
where Project.cID=#customerid
query returns only one cell, you can use SqlCommand.ExecuteScalar method which returns the first column of the first row as object.
For example;
sqlComm.CommandType = CommandType.StoredProcedure;
sqlComm.Parameters.AddWithValue("#customerid", id);
int value = (int)sqlComm.ExecuteScalar();
return value;

How to check if a row is present in SQL Server table or not?

I am trying to check if there is a row present in a SQL Server table or not.
If the row exists (on a particular TicketID), it should show a messagebox that you can't continue further as there is already an entry in database. But if there isn't, it should insert some records (on that particular TicketID).
I tried try and catch but wasn't able to do it :
Here is the code of query: (hardcoded ticketID for example)
bool no;
try
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ST"].ConnectionString.ToString());
con.Open();
cmd.CommandText = "SELECT EngineerVisited from tblTicketTechnical where TicketID=1";
cmd.Connection = con;
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
bool = rdr.GetBoolean(0);
}
con.Close();
}
catch
{
MessageBox.Show("Cannot continue");
}
I would really appreciate if someone could suggest a function that will return true if row is found and return false, if it isn't.
You should follow the same logic in code as the logic you state in English: if there's already a ticket show a message and if not, insert some data.
var checkQuery = "SELECT COUNT(*) FROM tblTicketTechnical where TicketID=1";
var command = new OleDbCommand(checkQuery, con);
con.Open();
int count = (int)command.ExecuteScalar();
if(count > 0)
{
//Already exists, show message
}
else
{
var insertQuery = "INSERT INTO tblTicketTechnical(col1, col2) VALUES('val1', val2')";
con = new OleDbCommand(insertQuery, con);
con.ExecuteNonQuery();
}
Please mind that this is written out of my head and not tested. Nor have I implemented exception handling. This is just to show the logic how you can perform what you want to achieve.
You can use HasRows property of SQLDataReader.
A catch block will only be executed if your code throws an exception. Here it is simply not happening.
Instead of Try/Catch use if statements and checks on your query results.
Create procedure and code like this
IF NOT EXISTS (SELECT 1 FROM youtable WHERE id= #id)
BEGIN
RAISERROR ('Record Exists', 16, 2)
END
ELSE
Begin
INSERT INTO YOURTABEL(COLUM1,COLUM2) VALUES(VALUE1, VALUE2)
END
and then by try catch you can show message to user
You can use DataTableReader.HasRows Property
The HasRows property returns information about the current result set

How to check Stored Procedures update result on C#

Looking on some source code I've inherited, there's a snippet of code that calls a SQL stored procedure making an Update.
The stored procedure returns -1 in case something goes wrong:
IF ##Error <> 0
BEGIN
ROLLBACK TRAN
SELECT -1
RETURN
END
COMMIT TRAN
SELECT 0
The C# code is something like this:
System.Data.SqlClient.SqlDataReader myReader;
try{
SqlDbConnection.Open();
SqlDbCommand.Connection = SqlDbConnection;
SqlDbCommand.CommandType = System.Data.CommandType.StoredProcedure;
SqlDbCommand.CommandText = "StoredProcedured_UpdateFoo";
SqlDbCommand.Parameters.Clear();
SqlDbCommand.Parameters.Add("#FooData", SqlDbType.DateTime); SqlDbCommand.Parameters["#FooData"].Value = System.DateTime.Now.ToString("yyyy-MM-dd");
myReader = SqlDbCommand.ExecuteReader();
if (myReader.Read())
{
if (int.Parse(myReader.GetValue(0).ToString()) == -1) throw new ErrorDataTxRx("Error FOO ");
}
} finally {
if (SqlDbConnection.State != ConnectionState.Closed){
SqlDbConnection.Close();
}
if (myReader != null){
if (!myReader.IsClosed) myReader.Close();
}
}
I also see part of the same code, checking the same thing using System.Data.DataSet() with Fill method.
Is there a more elegant way to check if the returned value is -1?
Is it OK to use an ExecuteReader in this case?
Have you tried using ExecuteScalar? That's designed for queries which return a single value:
Executes the query, and returns the
first column of the first row in the
result set returned by the query.
Additional columns or rows are
ignored
As Jon correctly noted, you're actually not using the return value of the SP, but actually getting the first value of the first row, which is what ExecuteScalar would do in a simpler way.
However, in order to get the return value from the SP (e.g. from something like RETURN #i; in the SP SQL code), you need to add a new Parameter and set its direction to ReturnValue, something like this:
SqlParameter returnValueParam = new SqlParameter();
returnValueParam.DbType = DbType.Int32;
returnValueParam.IsNullable = false;
returnValueParam.Direction = ParameterDirection.ReturnValue;
SqlDbCommand.Parameters.Add(returnValueParam);
// execute SP here...
int returnValue = (int)returnValueParam.Value;
Use ExecuteNonQuery instead of the reader and you will get the number of rows affected.
Your question is not clear enough. You may need to do it with a ReturnValue like Lucero has written.

Categories