Update multiple fields - c#

First of all i'm working with the MySQL-Connector / Net and a MySQL Database.
And please don't tell me that i should use using or i don't have try and catch. I have but i just wanted to post a low amount of code.
I want to update multiple fields at one but it is not working. I'm getting an syntax error.
(from comments)I'm getting this error:
MySql.Data.MySqlClient.MySqlException (0x80004005): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '+ 1, allC = allC + 50' at line 1
sql_command.CommandText = "Update Test Set x1 + 1 And allC + ?Ammount Where = 1;";
sql_command.Parameters.Add("?Ammount", MySqlDbType.Int32).Value = dataTable.Tables[0].Rows.Count;
sql_command.ExecuteNonQuery();
But isn't this right?
I don't really need the where clause because it is just a number table i would say, so there is not more than one row.
But it is also not working if it try it so:
sql_command.CommandText = "Update Test Set x1 + 1 And all + ?Ammount;";
And there is another question i have.
If i want to get one entry from a database and it's just really one, which is the easiest way to do that?
That's it, but how can i save this record in a string with a low amount of code?
sql_command.CommandText = "Select ID From Customer Order By ID Desc Limit 1;";

Assign your expressions to a column and use a comma (,) instead of And:
Update Test
Set x1 = x1 + 1, all = all + ?Ammount
Where = 1;
Also, your WHERE clause is invalid, but I need to more info to fix it for you.

Your SQL syntax for the UPDATE statement is broken beyond repair:
Update Test Set x1 + 1 And all + ?Ammount Where = 1;
To which field WHERE = 1 should refer to?
Which field should receive value of the x1 + 1?
I don't believe this question can be answered properly unless it is significantly revised; please provide some kind of a description on what you want to do with the UPDATE statement.
Also, last SELECT statement can be replaced by the following:
SELECT MAX(ID) FROM Customer;
This would be a bit more readable.

Related

Runing ExecuteNonQuery in C# for each different row

So I have a database that has student information and I want to add a randomly generated grade for each one of them.
I created a method that generates a random grade letter between A-F.
However, when I update my database table all the courses that the students are taking get the same grade I want to give each different course a different grade .
command.CommandText = "UPDATE CurrentCourses SET CurrenteGrade ='" +
RandomLetter(grades) + "'";
command.ExecuteNonQuery();
I believe that if there is a way to run this query for each different row it would solve my problem. But I couldn't really get it to work. I used Microsoft Access to create my database.
Thank you
The update statement affects all the rows in the database table:
"UPDATE CurrentCourses SET CurrenteGrade ='" +
RandomLetter(grades) + "'"
Without a WHERE clause, this code could be run in a loop 100 times with a random grade each time, but every row in the table will say whatever grade was randomized last. If the last loop picked 'E' as the random grade, then all rows in the table will be graded E, depite the fact that they have, in the previous 5 seconds, changed grade 99 times already (all rows change each time the code is run. They only stop changing when the code stops being executed)
If you want to change all course rows to the same grade:
sqlCommand.CommandText = "UPDATE CurrentCourses SET CurrenteGrade = ? WHERE Course_ID = ?";
And then populate the parameters of the SqlCommand:
sqlCommand.Parameters.AddWithValue("grade", RandomLetter(grades));
sqlCommand.Parameters.AddWithValue("course", "SoftwareEngineering101");
This is the sort of thing you'd run many times (in a loop maybe) with a different course ID each time. The idea is that you just change the parameter values, then re-run the query:
sqlCommand.CommandText = "UPDATE CurrentCourses SET CurrenteGrade = ? WHERE Course_ID = ?";
sqlCommand.Parameters.AddWithValue("grade", "a"); //dummy values
sqlCommand.Parameters.AddWithValue("course", "a"); //dummy values
//the loop does the real work, repeatedly overwiting param values and running:
foreach(var course in myCoursesArray){
sqlCommand.Parameters["grade"] = RandomLetter(grades);
sqlCommand.Parameters["course"] = course;
sqlCommand.ExecuteNonQuery()
}
With access, using ? for parameter placeholders in the SQL, it is important that you then add your paramters in the same order as the ? marks appear in the sql. The names are irrelevant - this is not so in more powerful DB systems like sqlserver, where the SQL has named parameters and the names given in the c# code do matter. In our Access based code though, the only thing that matters about the name is to use it when overwriting the parameter value with a new one in the loop
Note; there are good reasons to avoid using .AddWithValue, but I won't get into those here. It's more important to avoid using string concatenation to build values into your SQLs. See bobbytables.com for more info
First your exact question: You need a WHERE statement that filters the update down to just a single row. This is usually done with an ID number or other unique identifier for the specific row(student in this case).
Second: Concatenating strings together with raw data can lead to errors and also security issues. For example, things like having a single quote in your string data will cause havoc. You should use up SqlParameters. https://www.dotnetperls.com/sqlparameter
You could first query for each row in the table(s) that contain the students and the course.
And then for each row in the data set execute your method to update that row with a random letter grade.
for example
foreach (DataRow dr in ds.tables[0].rows)
{
command.CommandText = "UPDATE CurrentCourses SET CurrenteGrade ='" +
RandomLetter(grades) + "'" + "WHERE PRIMARYKEY = dr.id"
command.ExecuteNonQuery();
}
Try something like;
UPDATE CurrentCourses SET CurrenteGrade = (select top 1 gradeName from grades ORDER BY NEWID())
In your code, you are not setting different courses for students. Because before executing the query, your query takes just one grade and update all the rows.
You can perform it using SQL easily.
You can do it with pure T-SQL:
declare #idColumn int
DECLARE #MIN INT=1; --We define minimum value, it can be generated.
DECLARE #MAX INT=100; --We define maximum value, it can be generated.
select #idColumn = min( Id ) from CurrentCourses
while #idColumn is not null
begin
Update CurrentCourses
SET CurrenteGrade = #MIN+FLOOR((#MAX-#MIN+1)*RAND(CONVERT(VARBINARY,NEWID())));
select #idColumn = min( Id ) from CurrentCourses where Id > #idColumn
end
the code above is looping over all the records (replace Id with your primary key) and generates random number between 1-100 (see comments where you can set new values) and updates the random number in each CurrentGrade record.
format and concatenate that command into your CommandText and execute ExecuteNonQuery()
Using this UPDATE command without any WHERE-clause will affect every record each time. Note that the random letter is generated before the query is executed. Therfore the query will run with a single grade letter.
You could run this query for each course in turn with an appropriate WHERE-clause that selects one course each time. But this is not efficient.
Or, much better, you could apply a random function in SQL itself, that is evaluated for each record (i.e. let MySQL choose a random grade).
UPDATE CurrentCourses
SET CurrenteGrade = SUBSTRING('ABCDEF', FLOOR(RAND() * 6) + 1, 1)
In your code
command.CommandText = #"UPDATE CurrentCourses
SET CurrenteGrade = SUBSTRING('ABCDEF', FLOOR(RAND() * 6) + 1, 1)";
command.ExecuteNonQuery();
This requires no loops and no command parameters.
Note that RAND() returns a random number between 0.0 and 1.0 (including 0.0 but excluding 1.0). Therefore FLOOR(RAND() * 6) generates a whole number in the range [0 .. 5]. 1 is added to get a number in the range [1 .. 6] used as index in the string 'ABCDEF' for the SUBSTRING function that cuts out one letter.
Please put the where condition in your update query.Without where condition it will update all data in the table.

MySql.Data.MySqlClient for C#, time expires for a large MySql table

I am using MySql.Data.MySqlClient for C# in one of my applications.
At certain point, my .net application selects, from one large MySql table, which :
has two columns,
one column is the primary key ( PRI, int(11), auto increment )
other column is the column that contains some text, ( varchar(8000) )
one example entry for this column is:
info1=a;info2=b;cIndex=1;info4=d;info5=0.33;
just by chance, the entries on this very large table that includes the text segment "'%cIndex=1;%'" are before from the entries that includes the text segment for larger cIndex values, such as 34.
For instance:
the entry with a column2 value of
"info1=a;info2=b;cIndex=1;info4=d;info5=0.33"; is the 45566th entry
on this database,
whereas the entry with column2 value of
"info1=a;info2=b;cIndex=34;info4=d;info5=0.33;" is the 10,000,000th
entry on the table.
So basically, the entries with lower cIndex values are before from
the entries with higher cIndex values.
Key difference for this table from my earlier applications is that, the table I am running sql statement is "very large" by my standards;
with 2 columns
yet 24.6 million rows.
and with a data structure I mentioned above.
An example of the sql statement I am running from within my application is:
SELECT column2 FROM myLargeTable WHERE (column2 LIKE
'%info3=1;%') AND (column2 LIKE '%cIndex=0;%');
And, the method I am using in my c# application in order to run this query for a result is basically as follows:
public static string getInfoFromDb(string tbl, string col, string whr)
{
string myInfo = "error";
string sqlStr = "SELECT " + col + " from " + tbl + " " + whr + " " + " LIMIT 1 ";
MySqlConnection cn = new MySqlConnection(cstr);
cn.Open();
try
{
MySqlCommand co = new MySqlCommand(sqlStr, cn);
MySqlDataReader rd = co.ExecuteReader();
while (rd.Read()) { myInfo = rd.GetString(col); }
co.Dispose();
}
catch { /* do nothing */}
cn.Close();
return myInfo;
}
(So, the code is pretty much simple and it worked, for long years, for my databases where the tables sizes was much smaller at around, say, 70000+ rows)
My question is:
my sql statement returns the correct result when it is run from the
editor page of Toad-for-MySql, for any cIndex value - either it is a
smaller value such as 1, or a larger value such as 34. In any case,
the sql statement returns the correct result.
And, expectedly, this sql statement returns the correct result when the same sql statement is run, from within my C# application this time, when the cIndex value is small such as 1, i.e. SELECT column2 FROM myLargeTable WHERE (column2 LIKE '%info3=1;%') AND (column2 LIKE '%cIndex=1;%') returns the correct result.
But, interestingly, and this time unexpectedly, the very same sql statement returns error saying timeout expired when the same sql statement is run, from within my C# application, when the cIndex value of interest in the sql statement is larger, such as 34. i.e. SELECT column2 FROM myLargeTable WHERE (column2 LIKE '%info3=1;%') AND (column2 LIKE '%cIndex=34;%')
Any help is very much appreciated.
Thanks in advance for your time and considerations.
I figured out that the error is due to timeout for larger tables.
So, apparently, adding this line of code into my method solved the problem:
co.CommandTimeout = 600; // keep this value relatively large while working with large databases

SQL query not working properly in C# while a lot of data is applied one by one

I have a problem while reading from SQL Server in C#. It is happening in SSIS, I have inserted a C# script in data flow.
I am using the code below:
using (SqlConnection connection = new SqlConnection(connectionString))
{
string vendorName = Row.VendorName.ToString().Substring(0,1).ToUpper() + Row.VendorName.ToString().Substring(1);
using (SqlCommand command = new SqlCommand("Select TOP 1 * from Logs where MessageId = '" + Row.id.ToString() + "'" +
"AND name = (Select Id from Names where vendor_name = '" + vendorName +
"order by CreatedDate desc", connection))
{
connection.Open();
string status = "";
using (SqlDataReader oReader = command.ExecuteReader())
{
while (oReader.Read())
{
status = oReader["Status"].ToString();
}
}
if (String.IsNullOrEmpty(status))
{
SaveDataToDB(Row.id, Row.VendorName, "Unknown");
}
}
}
In the Logs table, there are about 10000 rows, and the related datasource, where Row data belongs to, has around 9000 records. The problem is that, even though the query is working well, in the script it sometimes brings status value as null, because it cannot find the record in the SQL. I am getting the query and copy/pasting it to SQL, executing the query brings result there, but not in C# somehow. For example, I am running the C# two times in sequence, at the first time it says Status is null for the id: 354456, but when I run it at the second time it finds 354456 correctly but saying that status of 354499 is null.
Any idea for me to solve this issue? I really appreciate for any help.
According to me, this could be due to order of evaluation of user defined values embedded within the query. Could be the first dynamic value might be evaluated before the one in the inner query.
As I am not sure about the value to variable binding, however, I would recommend you to check following points;
a) externalise both your variable (vendor name and row id) outside and evaluate and ensure it has respective values
b) and then form your query statement with the evaluated values
May be you can debug and see the CommandText of command object just before call Execute.
your code is really inefficient, you should cache vendorname in a string and do all the substring operations on that.
for example:
string vendorName = Convert.ToString(Row.VendorName);
vendorName = vendorName.Substring(0,1).ToUpper() + vendorName.Substring(1);
instead of selecting all the columns, select the specific column for a speed up select Status from.
try to debug your code first, see which id you are getting and what is the result of your query.
its really hard to debug your code without any debug information.
change your code to this (Select Id from Names where vendor_name = '" + vendorName + "')" and put a blank space next to every " character e.g. " AND instead of "AND

Error: You have an error in your SQL syntax - but SQL statement works

I am trying to iteratively update a MySql table in my c# app in a for loop. I am getting this error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '935 WHERE ID=1' at line 1
However, when I run my SQL statement in PhpMyAdmin, it is working well and it updates particular place in my table.
CODE:
for (int i = 1; i <= 10; i++)
{
string queryMean = " SELECT (RT1+RT2+RT3+RT4+RT5+RT6+RT7+RT8+RT9+RT10+RT11+RT12+RT13+RT14+RT15+RT16+RT17+RT18+RT19+RT20+RT21+RT22+RT23+RT24+RT25+RT26+RT27+RT28+RT29+RT30+RT31+RT32+RT33+RT34+RT35+RT36+RT37+RT38+RT39+RT40+RT41+RT42+RT43+RT44+RT45+RT46+RT47+RT48+RT49+RT50+RT51+RT52+RT53+RT54+RT55+RT56+RT57+RT58+RT59+RT60+RT61+RT62+RT63+RT64+RT65+RT66+RT67+RT68+RT69+RT70+RT71+RT72+RT73+RT74+RT75+RT76+RT77)/77 AS priem FROM reflextime WHERE reflextime.ID=" + i;
MySqlCommand cmd = new MySqlCommand(queryMean, conect);
readerMean = cmd.ExecuteReader();
readerMean.Read();
string result = readerMean["priem"].ToString();
double priem = Convert.ToDouble(result);
double priemer = Math.Round(priem, 3);
readerMean.Close();
string query2 = "UPDATE feture SET priemer="+priemer+" WHERE ID="+i;
MySqlCommand cmdx = new MySqlCommand(query2, conect);
cmdx.ExecuteScalar(); // here is the exception thrown
}
Thank you.
Be aware that if this runs on your machine (slovak culture settings) that the value in double priemer gets translated to string as e.g. "586,935". That is not what you want, as , has different meaning in SQL than ..
Simplest way to fix the problem is to use
string query2 = "UPDATE feture SET priemer="+priemer.ToString(CultureInfo.InvariantCulture)+" WHERE ID="+i;
You may have found this issue, if you printed the query2 before posting it here, by the way.
Be also aware that this is in no way a best practice to call a query in C#, a nice clue for how to create a parametrised query may be found here.

Npgsql parameterized query output incompatible with PostGIS

I have this parameterized query in an Npgsqlcommand:
UPDATE raw.geocoding
SET the_geom = ST_Transform(ST_GeomFromText('POINT(:longitude :latitude)', 4326),3081)
WHERE id=:id
:longutide and :latitude are double, and id is int.
The query that is actually run against the DB looks like this:
UPDATE raw.geocoding
SET the_geom = ST_Transform(ST_GeomFromText('POINT(((E'-96.6864379495382')::float8) ((E'32.792527154088')::float8))', 4326),3081)
WHERE id=((10793455)::int4)
Thanks to help from Erwin Brandstetter here, it's apparent that the query needs to be simplified to work with PostGIS. He suggested this:
UPDATE raw.geocoding
SET the_geom = ST_Transform(ST_GeomFromText(
$$POINT(:longitude :latitude)$$::geometry, 4326), 3081)
WHERE id = :id
I guess I could create this with a dynamic query, where I manually update the query every time I run it, but is there a way to make this work with a Npgsql parameterized query?
I am not an expert with npgsql, but I think your parameterized query could work like this:
UPDATE raw.geocoding
SET the_geom = ST_Transform(ST_GeomFromText(:mygeom, 4326), 3081)
WHERE id = :id
And mygeom would hold this string:
POINT(96.6864379495382 32.792527154088)
.. pre-assembled from your other variables. Would result in a query like this:
UPDATE raw.geocoding
SET the_geom = ST_Transform(ST_GeomFromText(
(E'POINT(96.6864379495382 32.792527154088)')::text, 4326),3081)
WHERE id=((10793455)::int4)
Which should work.
If you have trouble assembling the string (like your comment demonstrates), there is a more elegant way. As per hint from #Paul on my previous answer - PostGIS provides a dedicated function for the purpose:
ST_MakePoint(double precision x, double precision y)
Details in the manual. With this, we finally arrive at:
UPDATE raw.geocoding
SET the_geom = ST_Transform(ST_SetSRID(
ST_MakePoint(:longitude, :latitude), 4326), 3081)
WHERE id = :id
Note the comma. Will it finally work now?
If not, just beat it with a sledgehammer. Grml.
It does - with ST_SetSRID() now instead of ST_GeomFromText(). See comment.
In my case, I used:
NpgsqlCommand command = new NpgsqlCommand(
"select ST_Distance( ST_SetSRID(" +
"ST_MakePoint(#longitude, #latitude), 4326)," +
"(select geom from segments where segment_id= #id )," +
"true)",
m_DBConnection);
And it worked. Also, try with:
NpgsqlCommand command = new NpgsqlCommand(
"select ST_AsText( ST_ClosestPoint( ST_GeomFromText('POINT(" +
longitude.ToString(CultureInfo.GetCultureInfo("en-US").NumberFormat) + " " +
latitude.ToString(CultureInfo.GetCultureInfo("en-US").NumberFormat) + ")', 4326)," +
"(select geom from segments where segment_id= #id )))",
m_DBConnection);
Thanks.

Categories

Resources