I want to write an sql query to a file, but I'm only able to write one column of the query inside the text file. How do I add more columns ?
This is my c# windows form code:
SqlConnection con = new SqlConnection(#"Data Source=" + globalvariables.hosttxt + "," + globalvariables.porttxt + "\\SQLEXPRESS;Database=ha;Persist Security Info=false; UID='" + globalvariables.user + "' ; PWD='" + globalvariables.psw + "'");
SqlCommand command = con.CreateCommand();
command.CommandText = "Select * from bestillinger";
con.Open();
SqlDataReader queryReader = command.ExecuteReader();
while (queryReader.Read())
{
StreamWriter file = new StreamWriter(#"C:\Users\Michael\Desktop\query.txt");
file.WriteLine(queryReader["ordrenr"]);
file.Close();
}
queryReader.Close();
con.Close();
It wont allow me to write:
file.WriteLine(queryReader["ordrenr"] + queryReader["user"]);
I realize this six years old now, but seeing as I came across this in my own searching, I felt that offering a slightly cleaner answer would be good for others, as well. Also, I can't make comments yet, so I thought I might as well submit this as an answer.
The OP's answer presents a pretty major performance issue with recreating the stream with every row, as pointed out by Magus in the comments.
Meanwhile, mybirthname's answer actually never ends up adding a header row, and if the bool included is changed to true upon creation, it'll end up making a file filled with nothing but headers.
In this particular case, I'm writing the data out in a Comma Separated Value format. The file extension can be .csv if you want to open this in a spreadsheet editor afterwards, or .txt if it's not meant to be viewed by any end user.
//Consider putting your connection string in a config file and referencing it here.
SqlConnection sqlConn = new SqlConnection(Properties.Settings.Default.ConnString);
//If possible, avoid using "Select *" and instead, select only the columns you care about to increase efficiency.
SqlCommand sqlCmd = new SqlCommand("Select ordrenr, user From bestillinger", sqlConn);
sqlConn.Open();
SqlDataReader sdr = sqlCmd.ExecuteReader();
if (sdr.HasRows)
{
//There's really no reason to create the StreamWriter unless you actually find some data.
StreamWriter swExportWriter = new StreamWriter(#"C:\DataStore\Datafile.csv");
//Now that you know you have data, go ahead and write the first line to the file as the header row.
swExportWriter.WriteLine("ordrenr, user");
//Now use SqlDataReader.Read() to loop through the records and write each one to the file.
while (sdr.Read())
{
swExportWriter.WriteLine("{0},{1}", sdr["ordrenr"], sdr["user"]);
}
//Don't forget to close the StreamWriter!
swExportWriter.Close();
}
sdr.Close();
sqlConn.Close();
If you'd like to use Using statements instead, as per Magus' suggestion (which is probably a good idea), you can also structure it like so:
using (SqlConnection sqlConn = new SqlConnection(Properties.Settings.Default.ConnString))
{
SqlCommand sqlCmd = new SqlCommand("Select ordrenr, user From bestillinger", sqlConn)
sqlConn.Open();
using (SqlDataReader sdr = sqlCmd.ExecuteReader())
{
if (sdr.HasRows)
{
using (StreamWriter swExportWriter = new StreamWriter(#"C:\DataStore\Datafile.csv"))
{
swExportWriter.WriteLine("ordrenr, user");
while (sdr.Read())
{
swExportWriter.WriteLine("{0},{1}", sdr["ordrenr"], sdr["user"]);
}
}
}
}
}
I found a way:
file.WriteLine("{0},{1}", queryReader["ordrenr"], queryReader["user"]);
static void Main(string[] args)
{
string connString = #"here connection string";
SqlConnection con = new SqlConnection(connString);
SqlCommand command = con.CreateCommand();
command.CommandText = "Select * from Object";
con.Open();
SqlDataReader queryReader = command.ExecuteReader();
StreamWriter file = new StreamWriter(#"C:\Projects\EverydayProject\test.txt");
bool addColumns = false;
string columnName1="Title";
string columnName2 = "City";
while (queryReader.Read())
{
if(addColumns)
{
file.WriteLine(columnName1 + " " + columnName2);
addColumns = true;
}
else
{
file.WriteLine(queryReader["Title"].ToString() + " " + queryReader["City"].ToString());
}
}
queryReader.Close();
con.Close();
file.Close();
}
This is working you should first make the objects to String() also you need to close the file at the end. Not on first iteration !
Related
I'm frustrated because i can't solve this problem...
Well, i has been making a desktop application in C#, i almost complete the application,
But i have a big problem.
My application import an excel workbook who has some information that it is showed in a Gridview.
It works ok, but my app update or modified the data that is showed in a gridview, only one column that is called Balance.
I want to update this column in my excel workbook, is like an update condition in SQL, for example
I have this information that is imported to my app.
If i modify in my app some row, for example the row that has the order "12345", i want to update in my excel workbook the column called Balance of that row.
I has been trying with this code:
string order = textBox1.Text;
string balance = textBox2.Text;
filePath = openFileDialog1.FileName;
extension = Path.GetExtension(filePath);
header = "Yes";
OleDbConnection MyConnection = new OleDbConnection(conStr); ;
OleDbCommand myCommand = new OleDbCommand();
string sql = null;
MyConnection.Open();
myCommand.Connection = MyConnection;
sql = "UPDATE [" + sheetName + "] SET [" + sheetName + "].[Order]=123 WHERE [" + sheetName + "].[Balance]=12313";
myCommand.CommandText = sql;
myCommand.ExecuteNonQuery();
MyConnection.Close();
And if i debug the code it is the sentence that is executed, and i think that it is ok, but it doesn't works.
UPDATE ['12234$'] SET ['12234$'].[Order]=123 WHERE ['12234$'].[Balance]=12313
It give me this error:
Message=No value given for one or more required parameters.
Source=Microsoft Access Database Engine
Consider using an NuGet package to work with Excels instead. EPPlus is an excellent one.
using (var package = new ExcelPackage(#"someFile.xlsx")
{
var sheet = package.Workbook.Worksheets.First();
sheet.Cells["E2"].Value = 12345.32M;
package.Save();
}
Sql is no longer possible, but you can use Linq:
using (var package = new ExcelPackage(#"someFile.xlsx")
{
var sheet = package.Workbook.Worksheets.First();
int rowIndex = sheet.Cells["C2:C5"].First(x => int.Parse(x.Value.ToString()) == 12345).Start.Row;
const int balanceColumnIndex = 5;
sheet.Cells[rowIndex, balanceColumnIndex].Value = 12313M;
package.Save();
}
I wrote a series about EPPlus on my blog.
This is just a thought - but is your SQL-like string set up correctly?
If you're trying to update the balance for a certain order, you'd want that to be in your SET command.
So, something along the lines of...
UPDATE ['12234$'] SET ['12234$'].[Balance]=12313 WHERE ['12234$'].[Order]=12345
//try this solution
string connString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + Directory.GetCurrentDirectory() + "/swtlist.xlsx;" +
#"Extended Properties='Excel 12.0;HDR=Yes;';Persist Security Info=False;";
using (OleDbConnection connection = new OleDbConnection(connString))
{
connection.Open();
try
{
DataTable dt = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
OleDbCommand cmd = new OleDbCommand("UPDATE [Feuil1$] SET d='yes' ", connection);
cmd.ExecuteNonQuery();
connection.Close();
}
catch (Exception ex) { }
}
I'm trying to execute an RLOCK() command (record lock) on a FoxPro table via OleDbCommand but I need to know if the lock succeeded. In FoxPro, the RLOCK() returns .T. or .F. to indicate if it succeeded.
How do I get that result via OleDbCommand?
Here is my current code:
using(var conn = new OleDbConnection(...)) //connection string with VFPOLEDB provider
{
conn.Open();
using(var comm = new OleDbCommand())
{
string cText = #"[use table in 0] + chr(13) + "
+ #"[RLOCK(table)]";
comm.Connection = conn;
comm.CommandText = "Execute(" + cText + ")";
var result = comm.ExecuteNonQuery();
Consle.WriteLine(result);
comm.Dispose();
}
conn.Close();
conn.Dispose();
}
Right now, I'm always getting back a 1 (true) even when the Lock should not have taken place due to the fact that the record is already locked by someone else.
Thanks for your help.
Because you are not returning the result of the rlock() (and that you are using ExecuteNonQuery, when you should ask a return value and use ExecuteScalar instead). You would normally get back true with that code if you properly have used ExecuteScalar. In VFP each and every procedure returns .T. if no return value is specified (or call it a function if you will - in VFP procedure and function have no difference except name).
Here is a revised version of your code:
string myCode =
#"use c:\temp\lockTest
locked = rlock()
return m.locked
";
string strCon = #"Provider=VFPOLEDB;Data Source=c:\temp";
using (OleDbConnection con = new OleDbConnection(strCon))
{
OleDbCommand cmd = new OleDbCommand("ExecScript", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#code", myCode);
con.Open();
Console.WriteLine(cmd.ExecuteScalar());
con.Close();
}
While this code works perfectly well, I have no idea what you would do with a useless rlock() other than learning that you can't lock it due to some reason. In real life Execscript has little value.
I'm trying to search my local database table and simply display all it's columns.
I start my sending in
SearchID("1234");
My code so far:
private static void SearchID(string CostumerID)
{
string conStr = #"Data Source = C:\Users\secwp_000\documents\visual studio 2012\Projects\Module5\Module5\Orderdatabase.sdf";
DataSet ds = new DataSet();
SqlCeConnection con = new SqlCeConnection(conStr);
SqlCeCommand cmd = new SqlCeCommand("SELECT * FROM [Order]", con);
SqlCeDataReader dr = cmd.ExecuteReader();
SqlCeDataAdapter adapt = new SqlCeDataAdapter(cmd);
adapt.Fill(ds, "Order");
while (dr.Read())
{
string str = (string)dr[1];
if (str == CostumerID)
{
Console.WriteLine(str);
}
}
}
Where am I thinking wrong?
It stops on
SqlCeDataReader dr = cmd.ExecuteReader();
saying i don't have a connection. But just sounds wierd, because I've just had connection..
You have to open connection using
If(con.state.toString()=="closed")
con.open();
I observe a fault in your query why are you compare your result after fetch from database.you can directly filter in SQL query
Select * from order where table.customer_Id = customerId
You have a connection but you haven't opened it yet:
con.Open();
adapt.Fill(ds, "Order");
con.Close();
In addition you should use using statements for disposable objects like SqlConnection and SqlCommand to make sure they will be disposed properly:
using(SqlCeConnection con = new SqlCeConnection(conStr))
using(SqlCeCommand cmd = new SqlCeCommand("SELECT * FROM [Order]", con))
{
}
I feel so stupid for not seeing this, haha. And it worked! But it wont display anything from the table,
while (dr.Read())
{
string str = (string)dr[1];
if (str == CostumerID)
{
Console.WriteLine(str);
}
}
Following instructions given to me, there is nothing wrong with this code, and it could display Order with costumerID 1234.
UPDATE:
Thanks everyone, the code was not the issue, although the information regarding SQL injection was useful, my issue was that I was using an older version of my database which did not have the corresponding product ID so it was instead using the first product that it could find. Feel very stupid now but thanks for the suggestions.
I currently have the following code :
SqlConnection connection = new SqlConnection(#"Data Source=(LocalDB)\v11.0 AttachDbFilename=C:\Users\h8005267\Desktop\Practical Project\Build\System4\System\StockControl.mdf;Integrated Security=True;Connect Timeout=30");
connection.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM Product WHERE ProductID='" + textBox3.Text + "'", connection);
SqlDataReader re = cmd.ExecuteReader();
if (re.Read())
{
textBox4.Text = re["ProductTitle"].ToString(); // only fills using first product in table
textBox5.Text = re["ProductPublisherArtist"].ToString();
comboBox1.Text = re["ProductType"].ToString();
textBox6.Text = re["Price"].ToString();
}
else
{
MessageBox.Show("Please enter a valid item barcode");
}
re.Close();
connection.Close();
The issue I am currently having is although the text boxes display the information on button click, the information displayed is only the first row of data in the database, NOT the row corresponding to the textbox3 in the sql statement
Try this instead. Avoid building SQL statement dynamically the way you are doing it. You are opening your database to risks of SQL Injection. Used parameters insead.
using (var connection = new SqlConnection("connection string"))
{
connection.Open();
using (var cmd = new SqlCommand("SELECT * FROM Product WHERE ProductID=#MYVALUE", connection))
{
cmd.Parameters.Add("#MYVALUE", SqlDbType.VarChar).Value = textBox3.Text;
SqlDataReader re = cmd.ExecuteReader();
if (re.Read())
{
textBox4.Text = re["ProductTitle"].ToString(); // only fills using first product in table
textBox5.Text = re["ProductPublisherArtist"].ToString();
comboBox1.Text = re["ProductType"].ToString();
textBox6.Text = re["Price"].ToString();
}
else
{
MessageBox.Show("Please enter a valid item barcode");
}
}
}
put a breakpoint on that line
SqlDataReader re = cmd.ExecuteReader();
and enter the following into textBox3
'; DROP TABLE Product; SELECT '
the ' are to be entered in your textbox. now execute your method and carefully read the resulting sql command... welcome to sql injection ;)
#M Patel: thx for your comment and you are perfectly right
The result would be the following SQL
SELECT * FROM Product WHERE ProductID=''; DROP TABLE Product; SELECT ''
And this would allow a malicious user to destroy your database.
To prevent that you should work with prepared Statements like M Patel suggested in his answer
you have SQL Injection problem with '" + textBox3.Text + "'"
and you don't have to name your controls like that, you have to use a meaningful names
you can use this code
using (SqlConnection connection = new SqlConnection(#"Data Source=(LocalDB)\v11.0 AttachDbFilename=C:\Users\h8005267\Desktop\Practical Project\Build\System4\System\StockControl.mdf;Integrated Security=True;Connect Timeout=30"))
{
connection.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM Product WHERE ProductID=#ProductID", connection);
cmd.Parameters.AddWithValue("#ProductID", textBox3.Text);
SqlDataReader re = cmd.ExecuteReader();
if (re.Read())
{
textBox4.Text = re.GetString(re.GetOrdinal("ProductTitle")); // only fills using first product in table
textBox5.Text = re.GetString(re.GetOrdinal("ProductPublisherArtist"));
comboBox1.Text = re.GetString(re.GetOrdinal("ProductType"));
textBox6.Text = re.GetString(re.GetOrdinal("Price"));
}
else
{
MessageBox.Show("Please enter a valid item barcode");
}
re.Close();
}
In my code below, the cmdquery works but the hrquery does not. How do I get another query to populate a grid view? Do I need to establish a new connection or use the same connection? Can you guys help me? I'm new to C# and asp. Here's some spaghetti code I put together. It may all be wrong so if you have a better way of doing this feel free to share.
if (Badge != String.Empty)
{
string cmdquery = "SELECT * from Employees WHERE Badge ='" + Badge + "'";
string hrquery = "SELECT CLOCK_IN_TIME, CLOCK_OUT_TIME FROM CLOCK_HISTORY WHERE Badge ='" + Badge + "'";
OracleCommand cmd = new OracleCommand(cmdquery);
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
conn.Open();
OracleDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
this.xUserNameLabel.Text += reader["EMPLOYEE_NAME"];
this.xDepartmentLabel.Text += reader["REPORT_DEPARTMENT"];
}
OracleCommand Hr = new OracleCommand(hrquery);
Hr.Connection = conn;
Hr.CommandType = CommandType.Text;
OracleDataReader read = Hr.ExecuteReader();
while (read.Read())
{
xHoursGridView.DataSource = hrquery;
xHoursGridView.DataBind();
}
}
conn.Close();
Your data access code should generally look like this:
string sql = "SELECT * FROM Employee e INNER JOIN Clock_History c ON c.Badge = e.Badge WHERE e.Badge = #BadgeID";
using (var cn = new OracleConnection("your connection string here"))
using (var cmd = new OracleCommand(sql, cn))
{
cmd.Parameters.Add("#BadgeID", OracleDbType.Int).Value = Badge;
cn.Open();
xHoursGridView.DataSource = cmd.ExecuteReader();
xHoursGridView.DataBind();
}
Note that this is just the general template. You'll want to tweak it some for your exact needs. The important things to take from this are the using blocks to properly create and dispose your connection object and the parameter to protect against sql injection.
As for the connection question, there are exceptions but you can typically only use a connection for one active result set at a time. So you could reuse your same conn object from your original code, but only after you've completely finished with it from the previous command. It is also okay to open up two connections if you need them. The best option, though, is to combine related queries into single sql statement when possible.
I'm not even going to get into how you should be using usings and methods :p
if (Badge != String.Empty)
{
string cmdquery = "SELECT * from Employees WHERE Badge ='" + Badge + "'";
string hrquery = "SELECT CLOCK_IN_TIME, CLOCK_OUT_TIME FROM CLOCK_HISTORY WHERE Badge ='" + Badge + "'";
OracleCommand cmd = new OracleCommand(cmdquery);
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
conn.Open();
OracleDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
this.xUserNameLabel.Text += reader["EMPLOYEE_NAME"];
this.xDepartmentLabel.Text += reader["REPORT_DEPARTMENT"];
}
OracleCommand Hr = new OracleCommand(hrquery);
Hr.Connection = conn;
Hr.CommandType = CommandType.Text;
OracleDataReader read = Hr.ExecuteReader();
//What's this next line? Setting the datasource automatically
// moves through the data.
//while (read.Read())
//{
//I changed this to "read", which is the
//datareader you just created.
xHoursGridView.DataSource = read;
xHoursGridView.DataBind();
//}
}
conn.Close();