I have a stored procedure that returns 0 or 1 depending on certain outcomes. I often execute this procedure manually, so to have a description of the success/failure that's easily viewed in SSMS but still readable as 0/1 in code, I select the 0 or 1 as a different column name, i.e. SELECT 0 AS ThisReason or SELECT 0 AS ThatReason.
There is almost certainly a better way to handle this, but it got me curious - is it possible to read the name of the column you've selected when using ExecuteScalar in C#?
Not with ExecuteScalar but with ExecuteReader and SqlDataReader.GetName:
using (var con = new SqlConnection("connection-string"))
using (var cmd = new SqlCommand("storedprocedurename", con))
{
cmd.CommandType = CommandType.StoredProcedure;
// parameters here...
con.Open();
using (var rd = cmd.ExecuteReader())
{
if (rd.Read())
{
string column = rd.GetName(0); // first column
int value = rd.GetInt16(0); // or rd.GetInt32(0)
}
}
}
What you want to do is to get two bits of information as a result of a query. To use ExecuteScalar you will need to first "pack" those two bits into one. For example you could return a string starting with "+" or "-" indicating the success/failure, and the rest of the string could be a "reason".
There is no other way to do this with ExecuteScalar.
Related
I am developing a cricket simulation and i need to retrieve certain statistics from a players data. I've got the following code.
public List<float> BattingData()
{
con.ConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString.ToString();
string query = "SELECT [INNS], [NOT OUTS], [AVG] FROM [" + batTeam + "] WHERE [Player] = '" + name + "';";
SqlCommand com = new SqlCommand(query, con);
con.Open();
using (SqlDataReader reader = com.ExecuteReader())
{
if(reader.HasRows)
{
while (reader.NextResult())
{
Innings = Convert.ToInt32(reader["INNS"]);
NotOuts = Convert.ToInt32(reader["NOT OUTS"]);
Avg = Convert.ToSingle(reader["AVG"]);
}
}
}
con.Close();
OutRatePG = (Innings = NotOuts) / Innings;
OutRatePB = OutRatePG / 240;
RunsPB = Avg / 240;
battingData.Add(OutRatePB);
battingData.Add(RunsPB);
return battingData;
}
The error that I am getting is that when I try to divie by 'Innings' it is saying cannot divide by zero, so I think the variables are being returned as zero and no data is being assigned to them.
This line is the issue:
while (reader.NextResult())
What this does is move the reader to the next resultset, ignoring the rest of the rows unread. To advance a reader to the next row, you need to call reader.Read() instead.
You have some other issues with your code:
You appear to have a separate table for each team. This is incorrect database design. You should create a Team table, with each team in it, and then foreign key your TeamResults table to it. Query it using INNER JOIN.
You are concatenating user-entered values to your query. This leaves you open to SQL injection attacks. Use parameters instead. (You cannot parameterize a table name, another reason you should do as above 1.)
You do not need to check for HasRows. If there are no rows, Read() will return false.
It looks like you only want one row. If that is the case you don't want a while(reader.Read()) loop, instead if(reader.Read()). (If you only need a single value, you can refactor the code to use command.ExecuteScalar().)
In database records check if value for Innings has 0
also you can try the below code before performing any operation.
> if(Innings>0) { OutRatePG = (Innings - NotOuts) / Innings; }
I have the following method that sets an object to a specific status (it sets a column value of a specific row to '4' :
C#
void setObjectToFour(int objectID)
{
using (var conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Database"].ConnectionString))
using (var command = new SqlCommand("setObjectToFour", conn)
{
CommandType = CommandType.StoredProcedure
})
{
command.Parameters.Add(new SqlParameter("#objectID", SqlDbType.Int)).Value = objectID;
conn.Open();
command.ExecuteNonQuery();
}
}
SQL:
...
AS
BEGIN
Update [DB_OBJECT].[dbo].[object_table]
SET status = 4
WHERE id = #objectID
END
The problem is that the DB_OBJECT DB is not managed by us and is the DB of a piece of software.
The followed problem is that the query from above not always works (and we haven't figured out why) and I were thinking about how we could 'force' or 'check' if the row was updated.
Is it smart to do it as follow?:
1 - Create new C# Method Check and stored procedure getStatus that retrieves the status of the object
2 - I will put both methods from above in a do while until the status is 4.
Is this a smart approach?
ExecuteNonQuery() method returns the number of rows affected.
int recordAffectd = command.ExecuteNonQuery();
if (recordAffectd > 0)
{
// do something here
}
ExecuteNonQuery() does not return data at all: only the number of rows affected by an insert, update, or delete.
try this
if (command.ExecuteNonQuery() != 0)
{
// more code
}
I am new to SQL . As shown in the screenshot (SQL table) I want to get the circled cell value (3.4000) from this table and save it in a variable in C#. I just need the query and how to save it in a variable. Thank you in advance.
DECLARE #var float;
SET #var=(select Price2 from table where pizzaType='Hawaiian')
A bit generalized case. Providing that the RDBMS is MS SQL (if it's not your case, use appropriate Connection and Command classes instead of SqlConnection and SqlCommand ones) and you want Decimal value as a result
using (SqlConnection con = new SqlConnection(YourConnectionString)) {
con.Open();
using (SqlCommand q = con.CreateCommand()) {
q.CommandText = String.Format(
#"select {0}
from MyTable -- put actual table name here
where PizzaType = #prmPizzaType", "Price2");
q.Parameters.AddWithValue("#prmPizzaType", "Hawaiian");
using (var reader = q.ExecuteReader()) {
if (reader.Read()) {
// you may want to check if value is NULL: reader.IsDBNull(0)
Decimal value = Convert.ToDecimal(reader[0]);
if (reader.Read()) {
//TODO: At least 2 values: put your code here
}
}
else {
//TODO: no such value: put your code here
}
}
}
}
The query for this would be something along the lines of
select Price2 from <tablename> where PizzaType = "Hawaiian"
As far as storing the value, I believe this question will help with that: Reading values from SQL database in C#
I think it's not possible anymore like that. You need to store your query result in a DataGridView table, then take whatever you want from the DataGridView easily.
As the code Shows below, I want to insert a row into a database table (oracle 11) and return a String-Value of the inserted row.
using (OracleCommand cmd = con.CreateCommand()) {
cmd.CommandText = "insert into foo values('foo','bar') returning idString into :lastIdParam";
cmd.Parameters.Add(new OracleParameter("lastIdParam", OracleDbType.Varchar2), ParameterDirection.ReturnValue);
cmd.ExecuteNonQuery(); // returning 1 (insert row successfully)
var result = cmd.Parameters["lastIdParam"].Value.ToString(); // == String.Empty
}
Debugging shows that lastIdParam.Value's value = Empty.String:
My Problem is, that I'm not getting the return string into my return-parameter but it will work when returning an integer value (like sequence no of inserted id). Cast Problem? ...?
The idString is filled if running the Statement directly (or if I just do something like returning 'ABC' into :myOutputParameter
Any ideas how to retrieve a string after inserting row?
Have you tried setting a size for the parameter? The default size is 0.
new OracleParameter("lastIdParam", OracleDbType.Varchar2, 128)
The idString is an expression which has no value in your context, unless it is a column name in your table. Therefore, it is epected to be empty. You may change your query like the example below and see what happens.
cmd.CommandText = "insert into foo values('foo','bar') returning hereYouHaveToUseAColumnFromTheFooTable into :lastIdParam";
Situation: c#, sql 2000
I have a table, lets call it 'mytable' with 30 million rows.
The primary key is made up of fields A and B:
A char(16)
B smallint(2)
When i do a search like this, it runs really slowly (eg it does a full tablescan)
string a="a";
int b=1;
string sql = "select * from table(nolock) where a=#a and b=#b";
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("#a", a);
cmd.Parameters.AddWithValue("#b", b);
using (SqlDataReader rdr = cmd.ExecuteReader()) {...}
}
Change it to this however, and it runs really quick (eg it hits the index):
string where =
String.Format("a='{0}' and b={1}", a, b);
string sql = "select * from table(nolock) where " + where;
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
using (SqlDataReader rdr = cmd.ExecuteReader()) {...}
}
What on earth is going on? Seems strange to me.
Do data types of parameter and column match? They don't it appears so datatype precedence applies
The column is smallint, but you send int. The column will be converted to int because it has a higher precedence. So it won't use an index.
Does it make any difference if you declare the b variable to be a short instead of int?
Does it make any difference if you explicitly specify the types of the parameters?
Does it make any difference if you use "where a=#a and b=#b" instead of the comma form?
I agree this does sound odd, and I wouldn't really expect any of these changes to help, but it's probably worth a try.
You may tell SQL Server which index to use for a query. Use the WITH (INDEX = INDEX_ID) option where INDEX_ID is the ID of the index.
Get index ID's with:
SELECT i.indid, i.name FROM sysindexes i
INNER JOIN sysobjects o ON o.ID = i.id
WHERE o.Name = 'table'
So try then:
SELECT * FROM table(NOLOCK) WITH (INDEX = 1) WHERE a=#a and b=#b
As #gbn said, setting the data type should make it easy for you.
string where =
String.Format("a='{0}' and b={1}", a, b);
In the example above, you are telling SQL to treat parameter a as char.
Whereas, in other example it will be treated as a varchar.
Use SQL profiler to see what is the SQL that gets executed in both the cases. That should clear it for you.
In the first case you are adding SqlParameter classes to the command. When the command is executed it is most likely generating DECLARE statements with the wrong data type. (You can verify this with a SQL trace.) If this is the case, the optimizer cannot select the correct index and falls back to a table scan.
If you use a stored proc instead, you would be forcing the parameters into the data types you declare. However, you can still do this from code if you specify the SqlDbType on the parameters.