SQL SELECT With Stored Procedure and Parameters? - c#

I've been writing a lot of web services with SQL inserts based on a stored procedure, and I haven't really worked with any SELECTS.
The one SELECT I have in mind is very simple.
SELECT COUNT(AD_SID) As ReturnCount FROM AD_Authorization
WHERE AD_SID = #userSID
However, I can't figure out based on my current INSERT code how to make that into a SELECT and return the value of ReturnCount... Can you help? Here is my INSERT code:
string ConnString = "Data Source=Removed";
string SqlString = "spInsertProgress";
using (OleDbConnection conn = new OleDbConnection(ConnString))
{
using (OleDbCommand cmd = new OleDbCommand(SqlString, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("attachment_guid", smGuid.ToString());
cmd.Parameters.AddWithValue("attachment_percentcomplete", fileProgress);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
}

Here is where you are going wrong:
cmd.ExecuteNonQuery();
You are executing a query.
You need to ExecuteReader or ExecuteScalar instead. ExecuteReader is used for a result set (several rows/columns), ExecuteScalar when the query returns a single result (it returns object, so the result needs to be cast to the correct type).
var result = (int)cmd.ExecuteScalar();
The results variable will now hold a OledbDataReader or a value with the results of the SELECT. You can iterate over the results (for a reader), or the scalar value (for a scalar).

Since you are only after a single value, you can use cmd.ExecuteScalar();
A complete example is as follows:
string ConnString = "Data Source=Removed";
string userSid = "SomeSid";
string SqlString = "SELECT COUNT(AD_SID) As ReturnCount FROM AD_Authorization WHERE AD_SID = #userSID;";
int returnCount = 0;
using (OleDbConnection conn = new OleDbConnection(ConnString))
{
using (OleDbCommand cmd = new OleDbCommand(SqlString, conn))
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#userSID", userSid);
conn.Open();
returnCount = Convert.ToInt32(cmd.ExecuteScalar());
}
}
If you wanted to return MULTIPLE rows, you can use the ExecuteReader() method. This returns an IDataReader via which you can enumerate the result set row by row.

You need to use ExecuteScalar instead of ExecuteNonQuery:
String query = "SELECT COUNT(AD_SID) As ReturnCount FROM AD_Authorization WHERE AD_SID = #userSID ";
using (OleDbConnection conn = new OleDbConnection(ConnString)) {
using (OleDbCommand cmd = new OleDbCommand(query, conn))
{
cmd.Parameters.AddWithValue("userSID", userSID.ToString());
conn.Open();
int returnCount = (Int32) cmd.ExecuteScalar();
conn.Close();
}
}

cmd.executescalar will return a single value, such as your count.
You would use cmd.executereader when you are returning a list of records

Related

C# SQL Add parameter

I tried to return a row by executing following SQL query in C#:
SqlCommand cmd = new SqlCommand();
string selectquery = "SELECT TOP (1) [ZVNr] ZVNR_TABLE WHERE [ZVNr] = #zvnr order by [ZVNr] DESC";
cmd.Parameters.AddWithValue("#zvnr", "20170530-01");
cmd.CommandText = selectquery;
cmd.CommandType = CommandType.Text;
cmd.Connection = sqlConnection;
try
{
sqlConnection.Open();
int recordsAffected = cmd.ExecuteNonQuery();
if(recordsAffected != -1)
{
return 0;
}
else
{
return 1;
}
And the "ZVNR_TABLE" looks like this:
ZVNR | varchar (50)
20170530-01
The result is always --> recordsAffected = -1
Although when I'm executing the same SQL query in Microsoft SQL Server Management Studio, it works.
You're using a SELECT statement in your code with cmd.ExecuteNonQuery which is used for INSERT or UPDATE statements.
You have to use a SQLDataReader (more than 1 row and(!) column) or Scalar (1 row/1col = one "item").
MSDN Example for SQLDataReader:
//SELECT col1, col2, ..., coln FROM tbl;
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine("{0}\t{1}", reader.GetInt32(0),
reader.GetString(1));
}
}
else
{
Console.WriteLine("No rows found.");
}
reader.Close();
MSDN Example for ExecuteScalar:
//SELECT COUNT(*) FROM region; or any other single value SELECT statement
int count = (int)cmd.ExecuteScalar(); //cast the type as needed
If you want the affected count after you change items in your database, you can get it by using cmd.ExecuteNonQuery which returns that count:
MSDN Example for ExecuteNonQuery:
//INSERT INTO tbl (...) VALUES (...) or any other non-query statement
int rowsAffected = (Int32)cmd.ExecuteNonQuery();
For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command.
Because you are Selecting the data from the datatable not inserting or updating the records that's why recordsAffected is always -1
Answers given above are ok but if you want just to see if it exist you can do a count instead
using (SqlConnection connection = new SqlConnection(connectionstring))
{
string query = "SELECT Count([ZVNr]) ZVNR_TABLE WHERE [ZVNr] = #zvnr order by [ZVNr] DESC";
using (SqlCommand cmd = new SqlCommand(query, connection))
{
cmd.Parameters.AddWithValue("#zvnr", "20170530-01");
try
{
connection.Open();
int result = (int)cmd.ExecuteScalar();
}
}
}
ExecuteNonQuery() is used for INSERT or UPDATE statements and returns the number of rows affected.
If you want to return a single field of a row, you have to use ExecuteScalar()
using (SqlConnection connection = new SqlConnection(connectionstring))
{
string query = "SELECT TOP (1) [ZVNr] ZVNR_TABLE WHERE [ZVNr] = #zvnr order by [ZVNr] DESC";
using (SqlCommand cmd = new SqlCommand(query, connection))
{
cmd.Parameters.AddWithValue("#zvnr", "20170530-01");
connection.Open();
object result = cmd.ExecuteScalar();
}
}

C# Query MS-Access Table and place read values from column in a text box

Below is a snapshot of my code. I am trying to access the only column in the customer table and place the values into a textbox on the form. I keep getting the error with my code "InvalidOperationException was unhandled" at the line declaring dr as a OleDbDataReader object.
What do I have wrong with the below code that would be giving me this error?
Should I do a list to pick out the text I want from the database?
How can I return the column values from access into a list in C# so that I can search the list for a particular value?
string strsql = "Select * from Customer";
OleDbCommand cmd = new OleDbCommand();
cmd.CommandText = strsql;
conn.Open();
OleDbDataReader dr = cmd.ExecuteReader();
while(dr.Read())
{
textBox1.Text += dr["Customer"].ToString();
}
conn.Close();
A command carries the info to be executed, a connection carries the info to reach the database server. The two objects should be linked together to produce any result. You miss that line
OleDbCommand cmd = new OleDbCommand();
cmd.CommandText = strsql;
cmd.Connection = conn; // <= here
conn.Open();
Remember also that disposable objects like a command, a reader and a connection should be disposed immediately after usage. For this pattern exists the using statement
So you should write
string cmdText = "Select * from Customer";
using(OleDbConnection conn = new OleDbConnection(.....constring...))
using(OleDbCommand cmd = new OleDbCommand(cmdText, conn))
{
conn.Open();
using(OleDbDataReader reader = cmd.ExecuteReader())
{
while(reader.Read())
.....
}
}
Here is some sample code.
try
{
using (OleDbConnection myConnection = new OleDbConnection())//make use of the using statement
{
myConnection.ConnectionString = myConnectionString;
myConnection.Open();//Open your connection
OleDbCommand cmdNotReturned = myConnection.CreateCommand();//Create a command
cmdNotReturned.CommandText = "someQuery";
OleDbDataReader readerNotReturned = cmdNotReturned.ExecuteReader(CommandBehavior.CloseConnection);
// close conn after complete
// Load the result into a DataTable
if (readerNotReturned != null) someDataTable.Load(readerNotReturned);
}
}
After that you have a Datatable containing your data. Ofcourse you can afterwards search for records in the Datatable any way you like.

How to return a string value from datatable in c#?

I am getting unable to store datatable value in string . How to return a string value of a data table? It gives an error while returning scalar value.
An exception of type 'System.IndexOutOfRangeException' occurred in System.Data.dll but was not handled in user code-- error in return statement
txtSalespersonName.Text = dl.GetStringValue("select top 1 [ContactPerson] from tbl_Companies where Company='" +companyname + "' order by id desc");
public string GetStringValue(string query)
{
DataTable dt = new DataTable();
try
{
string constr = ConfigurationManager.ConnectionStrings["KernelCS"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand(query))
{
using (SqlDataAdapter sda = new SqlDataAdapter())
{
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
sda.SelectCommand = cmd;
sda.Fill(dt);
}
}
}
}
catch (Exception ex)
{
// Response.Write(ex.Message);
}
return dt.Rows[1].ToString();
}
To answer your question, error is occurring because DataTable is zero indexed based and your query is returning just 1 value thus it is out of range. dt.Rows[0][0].ToString() will give you correct output.
But Since you are returning a single value from the query, I would suggest you to use ExecuteScalar instead like this:-
string ContactPerson = String.Empty;
string constr = ConfigurationManager.ConnectionStrings["KernelCS"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand(query,con))
{
ContactPerson = cmd.ExecuteScalar().ToString();
}
}
return ContactPerson;
Also, use parametrized query to avoid SQL Injection attack.
dt.Rows[1] returns the second DataRow in your table which is not exist since your query returns only one row. You can use it as;
return dt.Rows[0][0].ToString();
But don't use SqlDataAdapter if you only get one row. Use ExecuteScalar which is exactly what this for.
using (var con = new SqlConnection(constr))
using (var cmd = con.CreateCommand())
{
cmd.CommandText = query;
con.Open();
return cmd.ExecuteScalar().ToString();
}
By the way, you should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.

Retrieving value from sql ExecuteScalar()

I have the following:
String sql = "SELECT * FROM Temp WHERE Temp.collection = '" + Program.collection + "'";
SqlConnection conn = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand(sql, conn);
Program.defaultCollection = (String)cmd.ExecuteScalar();
And I want to get the second column after executing the statement. I know it will return only one row with two columns
I have read online that I will have to read each row of the result, is there any other way?
ExecuteScalar gets the first column from the first row of the result set. If you need access to more than that you'll need to take a different approach. Like this:
DataTable dt = new DataTable();
SqlDataAdapater sda = new SqlDataAdapter(sql, conn);
sda.Fill(dt);
Program.defaultCollection = dt.Rows[0]["defaultCollection"];
Now, I realize that the field name may not be defaultCollection, but you can fill that in.
From the MSDN documentation for ExecuteScalar:
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.
Now, as a final bit of advice, please wrap all ADO.NET objects in a using statement. Like this:
using (SqlConnection conn = new SqlConnection(connString))
using (SqlDataAdapter sda = new SqlDataAdapter(sql, conn))
{
DataTable dt = new DataTable();
sda.Fill(dt);
// do something with `dt`
}
this will ensure they are properly disposed.
And I want to get the second column after executing the statement
It is not possible with execute scalar.
is there any other way
You have 2 options here either to use SqlDataAdapter or SqlDataReader.
For you using DataReader is a recommended approach as you don't need offline data or do other worh
by using SqlDataAdapter
using (SqlConnection c = new SqlConnection(
youconnectionstring))
{
c.Open();
/
using (SqlDataAdapter a = new SqlDataAdapter(sql, c))
{
DataTable t = new DataTable();
a.Fill(t);
if(t.Rows.Count > 0)
{
string text = t.Rows[0]["yourColumn"].ToString();
}
}
}
by using DataREader
using (SqlConnection connection =
new SqlConnection(connectionString))
{
SqlCommand command =
new SqlCommand(sql, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
//read data here
string text = reader.GetString(1)
}
reader.Close();
}
SqlCommand.ExecuteScalar() can be used only when the result have just one row and one column.
If you need more than one column to be returned, you should use something like this:
String sql = "SELECT * FROM Temp WHERE Temp.collection = '" + Program.collection + "'";
SqlConnection conn = new SqlConnection(connString);
using(SqlCommand cmd = new SqlCommand(sql, conn))
{
using(SqlDataReader rdr = cmd.ExecuteReader())
{
if(rdr.Read())
{
Program.defaultCollection = (String)rdr["Column1"];
Program.someOtherVar = (String)rdr["Column2"];
}
}
rdr.Close();
}
That will be the fastest way.
You can use a DataReader and read only the first column like:
IDataReader cReader = cmd.ExecuteReader();
if(cReader.Read())
{
string cText = cReader.GetString(1); // Second Column
}
ExecuteScalar only returns one value. You have to make sure your query only returns that value.
String sql = "SELECT temp.defaultCollection FROM Temp WHERE Temp.collection = '" + Program.collection + "'";
On a side note, read on SqlParameter. You don't want to concatenate values like that, you'll have a problem when the collection property contains a quote.

how to return int value from select query in function?

I need to retrieve Ticket_Id from tbl_Ticket to pass into body section of sending email function..
Is the below code correct?
every times i get Ticket_Id 1..
public int select_TicketId(){
string strConn = System.Configuration.ConfigurationManager.ConnectionStrings["conString"].ConnectionString.ToString();
SqlConnection sqlCon = new SqlConnection(strConn);
string getId = ("select Ticket_Id from tbl_Ticket where Client_EmailAdd='" + objNewTic_BAL.email + "' ");
sqlCon.Open();
SqlCommand cmd1 = new SqlCommand(getId, sqlCon);
int i=cmd1.ExecuteNonQuery();
return i;
}
You are searching for ExecuteScalar which returns the first value.
using System.Configuration;
//
public int select_TicketId()
{
string strConn = ConfigurationManager.ConnectionStrings["conString"].ConnectionString.ToString();
SqlConnection sqlCon = new SqlConnection(strConn);
string getId = ("select TOP 1 Ticket_Id from tbl_Ticket where Client_EmailAdd='" + objNewTic_BAL.email + "' ");
sqlCon.Open();
SqlCommand cmd1 = new SqlCommand(getId, sqlCon);
return Convert.ToInt32(cmd1.ExecuteScalar());
}
Also use CommandProperties to set the where statement for better security, like below:
public int select_TicketId()
{
string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
int result = -1;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandType = CommandType.Text;
command.CommandText = "select TOP 1 Ticket_Id from tbl_Ticket where Client_EmailAdd=#email";
command.Parameters.Add("#email", SqlDbType.Text).Value = objNewTic_BAL.email;
result = Convert.ToInt32(command.ExecuteScalar());
}
return result;
}
You should call int i=(int)cmd1.ExecuteScalar(); method
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalar.aspx
You're calling ExecuteNonQuery. But it's a query. This should have rung some warning bells :)
Try ExecuteScalar instead, and cast the result to int...
return (int) cmd1.ExecuteScalar();
Note that you should use using statements for the command and connection as well, so that both are closed appropriately.
And (I hadn't spotted this before) you should definitely use parameterized SQL instead of including a value directly into your SQL. Otherwise you're open to SQL Injection attacks...
So something like:
private const string FetchTicketIdSql =
"select Ticket_Id from tbl_Ticket where Client_EmailAdd = #Email";
public int FetchTicketId()
{
// No need for ToString call...
string connectionString =
ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(connection, FetchTicketIdSql))
{
command.Parameters.Add("#Email", SqlDbType.NVarChar).Value =
bjNewTic_BAL.email;
return (int) command.ExecuteScalar();
}
}
}
You should consider what you want to happen if there isn't exactly one result though...
Hiral,
ExecuteNonQuery in
int i=cmd1.ExecuteNonQuery();
will return number of records that satisfy your query. In this case it is 1 (or 0 if there are no emails)
Try using ExecuteReader instead.

Categories