Updating SQL column based on text file (foreach line in it) - c#

What I have is an extremely large text file that needs to go into a specific column at a specific raw. The file is around 100k lines. So what I want to do is read the whole file, and for each line append into that specific SQL column the line. Here's what I have but i really need help on the SQL query
string[] primaryfix = File.ReadAllLines(dinfo+"\\"+filex);
string filename = filex.ToString();
string[] spltifilename = filename.Split('.');
foreach (string primary in primaryfix)
{
string sqltable = ("dbo.amu_Textloadingarea");
string sql = "update " + sqltable + " set [Text] = [Text] + '" + primary + "' where begbates = '" + spltifilename[0] + "'";
SqlConnection con = new SqlConnection("Data Source= Corvette ;Initial Catalog= GSK_Avandia_SSECASE;Integrated Security= SSPI");
con.Open();
SqlCommand cmd = new SqlCommand(sql, con);
SqlDataReader reader = cmd.ExecuteReader();
con.Close();
}
everything is fine except for the string sql, it doesn't update the way I would like it to.
Any help is always appreciated.

Look likes you're trying to read from the database with that code inside the loop. SqlDataReader provides a way to read rows from the database, but not the other way around.
Replace
SqlDataReader reader = cmd.ExecuteReader();
with
cmd.ExecuteNonQuery();

The first thing I see is that you are not escaping the input from the text file; any SQL escape characters (like a single quote) will break that command. I'd recommend using parameters so you needn't worry about escapes at all.
Other than that, nothing pops to mind that would suggest why the command isn't working, but I do wonder if it might not cause fewer problems if it's such a large file to read it line-by-line rather than all at once.

Related

Use Variable In SQL String

How can I add a variable to my SQL string and run it against the server successfully? I want to run this statement through my C#
protected void RunSQLQuery(string salesman, string connectionString)
{
SqlConnection cnn;
SqlCommand cmd;
StringBuilder sql = new StringBuilder();
SqlDataReader reader;
cnn = new SqlConnection(connectionString);
sql = new StringBuilder();
sql.Append("update database ");
sql.Append("set shippdate = GetDate() ");
sql.Append("where salesman = "' + salesman + "'");
sql.Append("and managerapproval is not null ");
cnn.Open();
cmd = new SqlCommand(sql.ToString(), cnn);
reader = cmd.ExecuteReader();
reader.Close();
cmd.Dispose();
cnn.Close
}
This presents multiple compile errors underlining my +salesman+ code. The errors are:
Only assignment, call, increment, decrement, and new object
expressions can be used as a statement
; expected
) expected
Too many characters in character literal Newline in constant
You are not adding the string object that salesman refers, you are adding salesman as a string literal.
Just add it as a parameter like;
var cmd = new SqlCommand("update database set shippdate = GetDate() where salesman = #salesman");
cmd.Parameters.Add("#salesman", salesman);
...
And use ExecuteNonQuery to execute your command, not SqlDataReader. This SqlDataReader is for return some data.
But more important, you should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
Also use using statement to dispose your connection and command automatically instead of calling Close or Dispose methods manually.
As a full example;
protected void RunSQLQuery(string salesman, string connectionString)
{
using(var cnn = new SqlConnection(connectionString))
using(var cmd = cnn.CreateCommand())
{
cmd.CommandText = #"update database set shippdate = GetDate()
where salesman = #salesman";
// I assume your column is nvarchar
cmd.Parameters.Add("#salesman", SqlDbType.NVarChar).Value = salesman;
cnn.Open();
cmd.ExecuteNonQuery();
}
}
For myself, I always prefer to use SqlParameterCollection.Add(string, SqlDbType, Int32) overload to specify my parameter type and it's size but since you never mentioned your salesman column type, I couldn't post this in my example.
As you can also see from the syntax highlighting, the compile errors are caused because you did not escape the quotes properly in sql.Append("where salesman = "' + salesman + "'");.
As a side note, you should never insert strings into sql queries without first validating them, or you are open to sql injection, e.g. if i pass "''; drop table database;" as salesman parameter. It is better to use SqlParameter.
I would suggest using the AddWithValue method from your sql command combined with the UPPER function to make it case insensitive:
SqlCommand cmd = cnn.CreateCommand();
cmd.CommandText = "UPDATE database SET shippdate = GetDate() WHERE UPPER(salesman) = UPPER(#salesMan)";
cmd.Parameters.AddWithValue("#salesMan", salesman);
if (cnn.State.Equals(ConnectionState.Closed))
{
cnn.Open();
}
cmd.ExecuteNonQuery();
cnn.Close();
As mentioned in above answers, yes, writing queries in this way is not a good way to do it. But still if you want to do it that way only, you will have to change:
sql.Append("where salesman = "' + salesman + "'");
to
sql.Append("where salesman = '" + salesman + "'");

Sending information to a specific column in a database C#

I Have a table with 3 columns, when an alarm goes off, I want the time of that alarm to be stored in the 2nd column of the table(AlarmActivated). Then if that alarm is turned off, it stores that time in the same row of the table but in column 3. This is my code:
String ConStr = "Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\\PatientHealthMonitor.mdf;Integrated Security=True;Connect Timeout=30";
String Query = " INSERT INTO AlarmResponse (AlarmActivated) VALUES" + (DateTime.Now.ToString());
SqlConnection Con = new SqlConnection(ConStr);
SqlCommand Command = new SqlCommand(Query, Con);
Con.Open();
Command.ExecuteReader();
Con.Close();
This is executed when a value goes to 0.
ExecuteReader returns some data. Since you wanna insert, you need to use ExecuteNonQuery instead.
And do not store your DateTime values as a string. Change your column type to datetime2 and pass your DateTime.Now value directly to your parameterized query. Please read Bad habits to kick : choosing the wrong data type
Also using DateTime.Now can be ambigious. Read Matt's article The case against DateTime.Now
Use using statement to dispose your connection and command automatically instead of calling Close method manually.
Since you insert only one column, other two columns will be null or their default value.
string ConStr = "Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\\PatientHealthMonitor.mdf;Integrated Security=True;Connect Timeout=30"
using(var Con = new SqlConnection(ConStr))
using(var Command = Con.CreateCommand())
{
Command.CommandText = "INSERT INTO AlarmResponse (AlarmActivated) VALUES (#alarm)";
Command.Parameters.Add("#alarm", SqlDbType.DateTime2).Value = DateTime.Now;
Con.Open();
Command.ExecuteNonQuery();
}
The problem is in
String Query = " INSERT INTO AlarmResponse (AlarmActivated) VALUES" + (DateTime.Now.ToString())
It has to be
String Query = " INSERT INTO AlarmResponse (AlarmActivated) VALUES (" + DateTime.Now.ToString() + ")";
wrong function is used, use this function: https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executenonquery(v=vs.110).aspx ExecuteNonQuery
First, your string for your insert is badly formed. You need to put the parentheses inside quotes:
String Query = " INSERT INTO AlarmResponse (AlarmActivated) VALUES('" + DateTime.Now.ToString() +"')";
Secondly, you need to use parameterized queries instead, because building your SQL like this is a bad habit to get into and can lead to SQL injection breaches:
String ConStr = "Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\\PatientHealthMonitor.mdf;Integrated Security=True;Connect Timeout=30";
String Query = " INSERT INTO AlarmResponse (AlarmActivated) VALUES (#alarmTime)";
SqlConnection Con = new SqlConnection(ConStr);
SqlCommand Command = new SqlCommand(Query, Con);
Con.Open();
Command.Parameters.AddWithValue("#alarmTime", DateTime.Now);
Command.ExecuteNonQuery();
Con.Close();
Finally, only the column AlarmActivated will be set with a value. The other two columns will be populated by their default value. If you want the other two columns to have a value other than their default, you need to specify them and provide a value.
You can create 2 stored procedures in SQL, one will insert row and return ##SCOPE_IDENTITY (you can store it in list<>), which you will use as a param for updating procedure.
Try to avoid using SQL statemensts in code, to prevent code injection.

Saving strings from WPF to MySQL varchar

I have an WPF application that reads data from a file like so:
foreach (String line in File.ReadAllLines(file, Encoding.UTF8))
{}
Each line is then parsed and displayed on the screen which all works fine. Some of the data has cyrillic alphabet in it and the strings that I'm using to store this data in are also displayed fine on the screen in the app window.
However, after that I'm using those same strings to insert them into MySQL database. I'm building a query and firing it up MySqlCommand cmd = new MySqlCommand(query, conn); which successfully inserts a new line in the database with the appropriate information. Numbers are all fine, however all the strings that go into the database and have cyrillic letters are displayed as ????????
Database engine is InnoDB and the encoding of the table and all varchar fields in it is utf_general_ci so any idea what is going on and how can I save the correct string in the database?
EDIT:
Per request, here's some code. Database connection:
conn = new MySqlConnection();
conn.ConnectionString = "//censored//";
And the file reading / db loading, shortened for the purposes of this code snippet:
foreach (String line in File.ReadAllLines(file, Encoding.UTF8))
{
string[] tokens = line.Split('|');
string query = "INSERT INTO myTable SET first_name = '" + tokens[0] + "'" + ", last_name = '" + tokens[1] + "'";
MessageBox.Show(tokens[0]);
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.ExecuteNonQuery();
}
The message box shows the name as it should be but what goes into the database is ???????.
After some headbanging I did figure out where the problem is so posting an answer for all to see:
The key part is the way you establish your connection to the database:
conn.ConnectionString = #"Server = YOURSERVER; Database = YOURDB; Uid = YOURUSER ; Pwd = 'YOURPASSWORD'; charset=utf8;";
I was missing the charset=utf8; part before so I assume all kinds of non-utf8 junk was going to the database regardless of the fact that I was encoding in UTF8 on both sides of the connection. Hope this helps!

Access Database c# query Problems

Here is the background of my problem: I have a combobox that when users start typing, it should retrieve suggested items from a column in database table. The user starts inputing name and the program should suggest names by looking at both first and last names (database has separate tables for both )
Here is the code that I had:
try{
String temp = nameCBox.Text;
AutoCompleteStringCollection namesSuggestion = new AutoCompleteStringCollection();
OleDbConnection conn = new OleDbConnection("Provider=Microsoft.ACE.Oledb.12.0;Data Source=C:\\LogEntry\\LogEntry.accdb; Persist Security Info = False;");
OleDbDataReader reader;
conn.Open();
String text2send = "Select Name from [Teachers] where FName like '" + temp + "' OR LName like '" + temp + "' Group by [Name]";
OleDbCommand cmd = new OleDbCommand(text2send, conn);
reader = cmd.ExecuteReader();
if (reader.HasRows == true)
{
while (reader.Read())
namesSuggestion.Add(reader["temp"].ToString());
}
reader.Close();
nameCBox.AutoCompleteCustomSource = namesSuggestion;
conn.Close();
}
errors:
1) I see no suggestions in the combo box
2) When I type in the combo box, it highlights the text and when I type something else again, it will write on the previous typed character.
Please Help
desktopmaker
Erm
What's this doing
namesSuggestion.Add(reader["temp"].ToString());
reader is returning a column called Name..
I wouldunless the user is typing it in expect the search string to contain a wild card.
E.g. Like 'John%', or Like '%Smith' in standard sql, access uses * instead of % I seem to remember.
Oh and presumably you aren't worried about sql injection attacks??
Since you are using Like operator, try to make the input between look like this : %input%
To get something like :
Take a look at this, it may help
var sql = String.Format("Select Name from [Teachers] WHERE FName Like '%{0}%' OR LName Like '%{0}%'", temp);
Other points may be helpful about your current code :
Use the using statement in your code, it dispose the resources, and for the Connection, it close it.
using(var conn = new OleDbConnection("ConnectionStrong"))
{
//code
}
The best, is to use a parameterized query Link

import textfile into SQL table

I have a bunch of 2 line (with header row) '|' delimited text files. I need to import this into a specific SQL table and I'm having a hard time with the command.
string sqltable = ("dbo.SLT_C" + "60" + "Staging");
string[] importfiles= Directory.GetFiles(#"K:\jl\load\dest", "*.txt")
SqlConnection con = new SqlConnection("Data Source=" + "Cove" + ";Initial Catalog=" + "GS_Ava_MCase"+ ";Integrated Security=" + "SSPI");
con.Open();
foreach (string importfile in importfiles)
{
}
or maybe I am going about this the whole wrong way.
You could look at a ready-made solution, like FileHelpers. This FREE library allows you to define the structure of your file by means of a class describing the fields in your file, and then you can easily load the whole file into an array of that class type.
Once that's done, just simply iterate through the objects, and save them to your SQL Server.
Or check out the SQL Bulkcopy options:
bcp command line utility
SqlBulkCopy class in ADO.NET - also see this article at SQL Team
If you want to do it in "straight" ADO.NET, use something like this approach:
string sqltable = "dbo.SLT_C60Staging";
string[] importfiles = Directory.GetFiles(#"K:\jl\load\dest", "*.txt");
// try to wrap your ADO.NET stuff into using() statements to automatically
// dispose of the SqlConnection after you're done with it
using(SqlConnection con = new SqlConnection("Data Source=Cove;Initial Catalog=GS_Ava_MCase;Integrated Security=SSPI"))
{
// define the SQL insert statement and use parameters
string sqlStatement =
"INSERT INTO dbo.YourTable(DateField, TimeField, TextField) VALUES(#Date, #Time, #Text)";
// define the SqlCommmand to do the insert - use the using() approach again
using(SqlCommand cmd = new SqlCommand(sqlStatement, con))
{
// define the parameters for the SqlCommand
cmd.Parameters.Add("#Date", SqlDbType.DateTime);
cmd.Parameters.Add("#Time", SqlDbType.DateTime);
cmd.Parameters.Add("#Text", SqlDbType.VarChar, 1000);
// loop through all files found
foreach (string importfile in importfiles)
{
// read the lines from the text file
string[] allLines = File.ReadAllLines(importfile);
con.Open();
// start counting from index = 1 --> skipping the header (index=0)
for (int index = 1; index < allLines.Length; index++)
{
// split up the data line into its parts, using "|" as separator
// items[0] = date
// items[1] = time
// items[2] = text
string[] items = allLines[index].Split(new char[] { '|' });
cmd.Parameters["#Date"].Value = items[0];
cmd.Parameters["#Time"].Value = items[1];
cmd.Parameters["#Text"].Value = items[2];
cmd.ExecuteNonQuery();
}
con.Close();
}
}
}
That should work - you're question was too vague to know exactly what data will be in the lines, and what kind of SQL insert statement you'd need...
Using the text ODBC driver might work as well. In the ODBC administrator, you can choose the "Microsoft Access Text Driver". It allows you to choose the delimiter type. After setting up the data source, import to a data table. From there, it should be fairly simple to move the data into a SQL Server table.

Categories

Resources