I have in my class "fattura" this
public string sommaFattura(String costo)
{
MySqlCommand command = new MySqlCommand();
String sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
command.CommandText = sumQuery;
command.Connection = conn.getConnection();
command.Parameters.Add("#prezzo", MySqlDbType.Int32).Value = costo;
conn.openConnection();
//Need the command for take the result
conn.closeConnection();
}
What is the command for take the result of Sum query?
I want use this command, insert in a variable. Can you correct me?
I think the command you want is
command.ExecuteScalar();
However, note, Execute Scalar is intended that the result will return a single row, single column which your query does without regard to your parameter. However your query does not specifically make sense either..
Now your query itself. You have an explicit prezzo which would imply an existing column name and not that of a parameter. It would have to a numeric field for obvious reasons to sum it.
Now you also have an expected string coming in via "costo" parameter to the function call. If your intent is to have the incoming string be representative of a known column of the table, this is not going to work for you. You would have to build the SQL command with that explicit column name, or build doing dynamic-sql, but that would really be too much.
The concern with building a SQL statement with string parameters is you would be open to SQL-injection, especially if web-based. If your incoming string is coming from a controlled source, such as you are presenting a list of columns to a user and they can only pick one such column. Or, you have buttons on a screen asking for a sum of a certain thing, and YOU control that column name you would be in a better condition, but still be cautious passing parameter to build out SQL.
Say for example your table has numeric fields of qtySold and dollarSales. You want either the sum of either of these columns and are passing one of these respective strings into the function such as
var qtySoldAnswer = sommaFattura( "qtySold" );
or
var dollarSalesAnswer = sommaFattura( "dollarSales" );
Then your function would be CLOSER to...
public string sommaFattura(String costo)
{
MySqlCommand command = new MySqlCommand();
command.CommandText = "SELECT SUM(" + costo + ") FROM fatturetemp";
command.Connection = conn.getConnection();
conn.openConnection();
var answer = command.ExecuteScalar();
conn.closeConnection();
// I would put a breakpoint in here to see the results.
// you can then format the answer such as decimal point, etc.
return answer.ToString();
}
AGAIN, ONLY if YOU have control of the column name you are trying to send in. Someone could do sql-injection and do a lot of damage. I would only do with heavily controlled consideration and explicitly validating the columns you WOULD allow, and if so, set your variable at that point. Don't allow for any more or less than the column name. No special characters, quotes, comments, sql-terminator and new statement...
But hopefully this clarifies what I THINK you are trying to accomplish.
Related
Ok been starring at this for a good while and i can not under stand why it is not updating my database..... I do not get an error messages it runs just fine. Code below
if (e.KeyCode == Keys.Enter)
{
// #WORK
string searchtext = txtAssetScanned.Text;
string searchcmd = "UPDATE " + lstCompCode.SelectedItem.ToString() + " SET " + lstCompCode.SelectedItem.ToString() + ".[Inventory Status]= \"FOUND\" WHERE [Inventory number] like '*" + searchtext + "';";
MessageBox.Show(searchcmd);
myConnection.Open();
OleDbCommand search = new OleDbCommand();
search.Connection = myConnection;
search.CommandText = searchcmd;
search.ExecuteNonQuery();
myConnection.Close();
}
There are a few things that pop out here :
Use Parameterized Queries. You should be using parameterized queries, concatenating in the manner you currently are can cause syntax issues and leave you vulnerable to SQL Injection.
Consider Using Single Quotes for Values. When setting string values in SQL, you should use single quotes 'value' as opposed to double quotes (i.e. "value").
SelectedValue over SelectedItem. Consider using the SelectedValue property as opposed to SelectedItem.ToString() to ensure you use the proper value.
Table Names as Parameters May Not Be Allowed. If you are using a table name as a parameter, which in many cases may be flat out rejected (as they are generally reserved for values), so fair warning.
Double-check for Typos. Finally, ensure the properties that you are targeting are correct and do not contain any typos (i.e. Foo.[Inventory number], etc.)
You can apply these changes as follows :
using(var connection = new OleDbConnection("{your-connection-string}"))
{
// Build your query with parameters
var query = "UPDATE ? SET [Inventory Status] = 'FOUND' WHERE [Inventory number] LIKE ?";
using(var command = new OleDbCommand(query, connection))
{
connection.Open();
// Add your parameters
command.Parameters.AddWithValue("#table",lstCompCode.SelectedValue);
command.Parameters.AddWithValue("#search", "*" + txtAssetScanned.Text);
// Now that your queries are added, perform your update
command.ExecuteNonQuery();
}
}
The Likely Issue
As I mentioned, some databases will not allow you to pass in table names as parameters without resorting to stored procedures, dynamic SQL, etc. You may be better off simply defining the table that you want to use directly :
var query = "UPDATE [YourTableName] SET [Inventory Status] = 'FOUND' WHERE [Inventory number] LIKE ?";
Since you cannot pass this through via parameters, you might consider adding some logic to determine which to use and hard-code it along with some sanitation to avoid possible nefarious behavior.
I'm attempting to pass a string of numbers into a query that will run against our AS400 connection however it doesn't seem that my value is actually making it to the query. I am returning a result when I debug to the point of the parameter so I know I'm getting my number.
var command = new OleDbCommand("SELECT UMACT, UMCUS, UMNAM, UMAD1, UMAD2, UMAD3, UMZIP, UMOPH, UMSLC FROM CFFILES.UMST WHERE trim(UMEMT) = '?' ", connection);
//Test meter number: 59115796
connection.Open();
OleDbParameterCollection paramCollection = command.Parameters;
paramCollection.Add(meternumber.ToString(), OleDbType.LongVarChar);
When I pass a number directly into the query it returns a perfect result however when I try to pass a number from the parameter it returns null.
Here is the variable itself that I know is being passed to my parameter that I created above because I get a result when I debug to that line.
public IEnumerable<CustomerInfoModel> GetCustomerInfo()
{
int meternumber = 59115796;
getAS400Data(meternumber);
return customerList;
}
For my AS400 query to work I have to have the ticks around the ? in the query so I'm not sure if that is perhaps causing the issue.
You have the call to Add method wrong. The first parameter of Add is the Name of the parameter, the second is the DataType and finally you should set the value of the parameter in this way
OleDbParameterCollection paramCollection = command.Parameters;
paramCollection.Add("whatever", OleDbType.LongVarChar).Value = meternumber.ToString();
See OleDbParameterCollection.Add
And no, you shouldn't add ticks around the question mark placeholder. If you do you transform your placeholder in a literal string and obviously you don't have any row with a question mark as value.
A final note, in OleDb parameters doesn't have a name, but when you add them to your collection you should provide one so you are free to choose whatever you like for the name. Just remember to keep them in the same order in which the placeholders (?) appears in your query string
I have a list Called ListTypes that holds 10 types of products. Below the store procedure loops and gets every record with the product that is looping and it stores it in the list ListIds. This is killing my sql box since I have over 200 users executing this constantly all day.
I know is not a good architecture to loop a sql statement, but this the only way I made it work. Any ideas how I can make this without looping? Maybe a Linq statement, I never used Linq with this magnitude. Thank you.
protected void GetIds(string Type, string Sub)
{
LinkedIds.Clear();
using (SqlConnection cs = new SqlConnection(connstr))
{
for (int x = 0; x < ListTypes.Count; x++)
{
cs.Open();
SqlCommand select = new SqlCommand("spUI_LinkedIds", cs);
select.CommandType = System.Data.CommandType.StoredProcedure;
select.Parameters.AddWithValue("#Type", Type);
select.Parameters.AddWithValue("#Sub", Sub);
select.Parameters.AddWithValue("#TransId", ListTypes[x]);
SqlDataReader dr = select.ExecuteReader();
while (dr.Read())
{
ListIds.Add(Convert.ToInt32(dr["LinkedId"]));
}
cs.Close();
}
}
}
Not a full answer, but this wouldn't fit in a comment. You can at least update your existing code to be more efficient like this:
protected List<int> GetIds(string Type, string Sub, IEnumerable<int> types)
{
var result = new List<int>();
using (SqlConnection cs = new SqlConnection(connstr))
using (SqlCommand select = new SqlCommand("spUI_LinkedIds", cs))
{
select.CommandType = System.Data.CommandType.StoredProcedure;
//Don't use AddWithValue! Be explicit about your DB types
// I had to guess here. Replace with the actual types from your database
select.Parameters.Add("#Type", SqlDBType.VarChar, 10).Value = Type;
select.Parameters.Add("#Sub", SqlDbType.VarChar, 10).Value = Sub;
var TransID = select.Parameters.Add("#TransId", SqlDbType.Int);
cs.Open();
foreach(int type in types)
{
TransID.Value = type;
SqlDataReader dr = select.ExecuteReader();
while (dr.Read())
{
result.Add((int)dr["LinkedId"]);
}
}
}
return result;
}
Note that this way you only open and close the connection once. Normally in ADO.Net it's better to use a new connection and re-open it for each query. The exception is in a tight loop like this. Also, the only thing that changes inside the loop this way is the one parameter value. Finally, it's better to design methods that don't rely on other class state. This method no longer needs to know about the ListTypes and ListIds class variables, which makes it possible to (among other things) do better unit testing on the method.
Again, this isn't a full answer; it's just an incremental improvement. What you really need to do is write another stored procedure that accepts a table valued parameter, and build on the query from your existing stored procedure to JOIN with the table valued parameter, so that all of this will fit into a single SQL statement. But until you share your stored procedure code, this is about as much help as I can give you.
Besides the improvements others wrote.
You could insert your ID's into a temp table and then make one
SELECT * from WhatEverTable WHERE transid in (select transid from #tempTable)
On a MSSQL this works really fast.
When you're not using a MSSQL it could be possible that one great SQL-Select with joins is faster than a SELECT IN. You have to test these cases by your own on your DBMS.
According to your comment:
The idea is lets say I have a table and I have to get all records from the table that has this 10 types of products. How can I get all of this products? But this number is dynamic.
So... why use a stored procedure at all? Why not query the table?
//If [Type] and [Sub] arguments are external inputs - as in, they come from a user request or something - they should be sanitized. (remove or escape '\' and apostrophe signs)
//create connection
string queryTmpl = "SELECT LinkedId FROM [yourTable] WHERE [TYPE] = '{0}' AND [SUB] = '{1}' AND [TRANSID] IN ({2})";
string query = string.Format(queryTmpl, Type, Sub, string.Join(", ", ListTypes);
SqlCommand select = new SqlCommand(query, cs);
//and so forth
To use Linq-to-SQL you would need to map the table to a class. This would make the query simpler to perform.
Hello so i m creating a registration form in C# with MySql so it connects to the database and everything but i get this error Napaka pri registraciji Unknown column " in 'field list' the translation of Napaka pri registraciji means Error at registering i just have it in my language. I get this error when i insert data in textboxes and press Register..
the code:
private void btn_Reg_Click(object sender, EventArgs e)
{
MySqlConnection dataConnection = new MySqlConnection();
dataConnection.ConnectionString = "datasource=localhost;port=3306;username=root;password=";
dataConnection.Open();
MySqlTransaction transakcija = dataConnection.BeginTransaction();
MySqlCommand dataCommand = new MySqlCommand();
dataCommand.Connection = dataConnection;
dataCommand.Transaction = transakcija;
try
{
dataCommand.CommandText = "Insert INTO lr.users (upIme,geslo) VALUES (`"+this.tB_upIme.Text+"`,`"+this.tB_geslo.Text+"`)";
dataCommand.CommandType = CommandType.Text;
dataCommand.ExecuteNonQuery();
transakcija.Commit();
MessageBox.Show("Registracija uspešna!");
}
catch (Exception eks)
{
transakcija.Rollback();
MessageBox.Show("Napaka pri registraciji\n" + eks.Message);
}
finally
{
dataCommand.Connection.Close();
}
}
There are two things I immediately see wrong here...
First, you're using back ticks to wrap your values. In MySQL Back ticks represent database objects, so the query is looking for objects named by those values instead of using the values themselves. So instead of this:
`"+this.tB_upIme.Text+"`
You'd want this:
'"+this.tB_upIme.Text+"'
Second, and vastly more importantly, your code is wide open to SQL injection attacks. You'll want to use query parameters, not direct string concatenation. While it may look like you're just putting values into the query string, you're actually taking user input and treating it as executable code in your query string, which means users can run any arbitrary code they want on your database.
First, add parameters to your query:
"Insert INTO lr.users (upIme,geslo) VALUES (#upIme, #geslo)"
(You'll notice this also makes the query a heck of a lot cleaner and easier to read.) Then add your parameters to the command:
dataCommand.Parameters.AddWithValue("#upIme", this.tB_upIme.Text);
dataCommand.Parameters.AddWithValue("#geslo", this.tB_geslo.Text);
Then when you execute that command it will treat the user-input values as values instead of as executable code.
Change to single quotes ' in the values.
dataCommand.CommandText =
"Insert INTO lr.users (upIme,geslo)
VALUES ('"+this.tB_upIme.Text+"','"+this.tB_geslo.Text+"');";
I am executing a SQL Server stored procedure from my C# code which essentially pulls some data from a database based on the supplied condition.
DataSet GetAllxxxxxByDate(string entityValue,string companyValue)
{
using (var sqlConn = new SqlConnection(GetConnectionString()))
{
using (var cmd = new SqlCommand())
{
var data = new DataSet();
cmd.CommandText = “myStoredprodecure”;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = sqlConn;
var eVal = string.IsNullOrWhiteSpace(entityValue) ? string.Empty : entityValue;
cmd.Parameters.AddWithValue("#entity_value", eVal);
var company = string.IsNullOrWhiteSpace(companyValue) ? string.Empty : companyValue;
cmd.Parameters.AddWithValue("#company", company);
var sqlDataAdaptor = new SqlDataAdapter(cmd);
sqlDataAdaptor.Fill(data);
return data;
}
}
}
Here entityValue, companyValue are comma separated strings, formed dynamically within C# code and pass it to stored procedure.
Eg:
’first’,’second’,’third’
And the stored procedure uses these values to fill the NOT IN condition defined within it.
The issue is that, I am getting inconsistent number of records when I execute the code.
Following is a quick screenshot where first WHERE clause return 3 records and second WHERE clause return 1 record. The input values for the first WHERE clause is been filled from c# code and the second is been filled manually to test.
The only difference, which I can spot is number of quotes.
Question: can someone help me to zero in the issue or the difference in these give WHERE clause ?
Well, you don't show what entity_value is in your results, but the difference between the two is you're adding single quotes around the literal values:
N'''FSEC''' in SQL is the literal valiue 'FSEC'
'FSEC' in SQL is just FSEC (without the quotes).
My guess is that records 2004981 and 2004982 have a value of FSEC (without the quotes) for entity_value.
If you're adding parameter values from C# code, don't add quotes around them like you would if you were building a string. SQL will treat the values as strings without needing string qualifiers.
EDIT
Okay, I just read this statement:
Here entityValue, companyValue are comma separated string
You can't just pass in a comma-delimited string to an IN clause. To search for multiple values there are a few options:
Add commas to each end and use LIKE:
Where (',' + #entity_value +',' LIKE '%,' + entity_value + ',%')
Parse the string into a temporary table, than use that table in your IN clause
Pass the values as a table-valued parameter and use that in your IN clause.
Build the SQL statement as a string and execute it with EXEC