Here is my code to get data from a flat file and insert into SQL Server. It is generating an exception (Index was outside the bounds of the array).
string path = string.Concat(Server.MapPath("~/TempFiles/"), Fileupload1.FileName);
string text = System.IO.File.ReadAllText(path);
string[] lines = text.Split(' ');
con.Open();
SqlCommand cmd = new SqlCommand();
string[] Values = new string[3];
foreach (string line1 in lines)
{
Values = line1.Split(';');
string query = "INSERT INTO demooo VALUES ('" + Values[0] + "','" + Values[1] + "','" + Values[2] + "')";
cmd = new SqlCommand(query,con);
cmd.ExecuteNonQuery();
}
The exception happens because one of your lines has less than three elements separated with a semicolon. Even though you declare Values as a String array of three elements, affecting the variable to the result of String.Split() function makes that irrelevant: your array will have whatever length the returned array has. If it's less, your code will definitely fail.
If it's not supposed to happen I suggest you do an assertion in your code to help you debugging:
// ...
Values = line1.Split(';');
// the following will make the debugger stop execution if line.Length is smaller than 3
Debug.Assert(line1.Length >= 3);
// ...
As a side note, I should mention making a batch INSERT would be far more efficient. Also your way of declaring and reaffecting cmd variable isn't quite correct. And finally you should call String.Replace on your values to make sure any apostrophes is doubled. Otherwise your code will be open for SQL injection attacks.
Some details on how your code is behaving at run-time:
// This line declares a variable named Values and sets its value to
// a new array of strings. However, this new array is never used
// because the loop overwrites Values with a new array before doing
// anything else with it.
string[] Values = new string[3];
foreach (string line1 in lines)
{
Values = line1.Split(';');
// At this point in the code, whatever was previously stored in Values has been
// tossed on the garbage heap, and Values now contains a brand new array containing
// the results of splitting line1 on semicolons.
// That means that it is no longer safe to assume how many elements the Values array has.
// For example, if line1 is blank (which often happens at the end of a text file), then
// Values will be an empty array, and trying to get anything out of it will throw an
// exception
string query = "INSERT INTO demooo VALUES ('" + Values[0] + "','" + Values[1] + "','" + Values[2] + "')";
cmd = new SqlCommand(query,con);
cmd.ExecuteNonQuery();
}
Similar to how Values keeps getting overwritten, that SqlCommand that's created outside the loop will also never get used. It's safe to put both of these declarations inside the loop instead. The following code does that, and also adds some error checking to make sure that a usable number of values was retrieved from the line. It will simply skip any lines that aren't long enough - if that's not OK then you might need to create some more complex error-handling code of your own.
foreach(string line in lines)
{
string[] values = line.split[';'];
if(values.Length >= 3)
{
string query = "INSERT INTO demooo VALUES ('" + Values[0] + "','" + Values[1] + "','" + Values[2] + "')";
using (SqlCommand command = new SqlCommand(query, con))
{
cmd.ExecuteNonQuery();
}
}
}
As one final note, the above code might be vulnerable to hackers if you were using it in something like a Web application. Think about what command might get sent to the server if you were processing a file that looked like this:
1;2;3
4;5;6
7;8;9') DROP TABLE demooo SELECT DATALENGTH('1
A safer option is to use parameterized queries, which will help protect against this kind of attack. They do this by separating the command from its arguments, which helps protect you against passing in values for arguments that look like SQL code. An example of how to set things up that way would look more like this:
string query = "INSERT INTO demooo VALUES (#val1, #val2, #val3);
using (var command = new SqlCommand(query, con))
{
command.Parameters.AddWithValue("#val1", Values[0]);
command.Parameters.AddWithValue("#val2", Values[1]);
command.Parameters.AddWithValue("#val3", Values[2]);
command.ExecuteNonQuery();
}
Try this.
string path = string.Concat(Server.MapPath("~/TempFiles/"), Fileupload1.FileName);
string text = System.IO.File.ReadAllText(path);
string[] lines = text.Split(' ');
con.Open();
string[] Values;
foreach (string line1 in lines)
{
Values = line1.Split(';');
if (Values.Length >= 3)
{
string query = "INSERT INTO demooo VALUES ('" + Values[0] + "','" + Values[1] + "','" + Values[2] + "')";
}
else
{
//Some error occured
}
using (var cmd = new SqlCommand(query,con))
{
cmd.ExecuteNonQuery();
}
}
Related
Basically I have this list of students (alunos) and I want to double click in one of the students and I want it to show a MessageBox containing:
Student No.: {student no. from the selected student here}
Name: {student name from the selected student here}
etc...
Here's the code I have:
void lstAlunos_MouseDoubleClick(object sender, MouseEventArgs e)
{
string query = "SELECT * FROM (" +
"SELECT" +
"ROW_NUMBER() AS rownumber," +
"columns" +
"FROM Alunos" +
") AS foo" +
"WHERE rownumber = " + lstAlunos.SelectedIndex;
using (connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(query, connection))
using (var reader = command.ExecuteReader())
{
connection.Open();
reader.Read();
string numAluno = reader.GetString(0);
string nomeAluno = reader.GetString(1);
string apelidoAluno = reader.GetString(2);
string contactoAluno = reader.GetString(3);
string emailAluno = reader.GetString(4);
}
int index = this.lstAlunos.IndexFromPoint(e.Location);
if (index != System.Windows.Forms.ListBox.NoMatches)
{
MessageBox.Show("Nome: " + nomeAluno);
}
}
Add spaces to the ends of the strings you're concatenating. Right now this segment:
"columns" +
"FROM" +
will give you "columnsFROM" which is obviously bad SQL.
Some other suggestions:
Add error handling. The exception you got from this should give you a clue as to where the problem is.
Use parameters instead of concatenating string values. It will protect you from SQL Injection attacks and take care of formatting for you.
Don't use ROW_NUMBER() without some sore of explicit order. THere's no guarantee that you'll get the rows in the same order that they were saved in previously. Use an ID column instead.
Here is postgresql running query with pg admin iii. (Below query working fine with pg admin and it is returning result set without any issue)
select * from pg_sp_getmainrates_11(9,10,array[[5,10,10,10],[30,20,15,16]]);
Here is parameter declaration of pg function.
CREATE OR REPLACE FUNCTION pg_sp_getmainrates_11(
IN fromcountryid integer,
IN tocountryid integer,
IN alldimensions_we_le_he_wi double precision[]
)
-- My logic is going here
But when passing array using C# code, it is returning error when executing the query.
Exeption attributes
Basemessage : syntax error at or near ","
ErrorSql : SELECT * FROM pg_sp_getmainrates_11(9,10,System.Double[,])
Here is my C# code.
double[,] codes = new double[,]
{
{ 5,10,10,10},{ 30,20,15,16}
};
string quy = "pg_sp_getmainrates_11(" + FromCountryId +
"," + ToCountryId +
"," + codes + ")";
NpgsqlCommand command = new NpgsqlCommand(quy, conn);
command.CommandType = CommandType.StoredProcedure;
NpgsqlDataReader dr = command.ExecuteReader();
I need a small direction to pass an array (like above) to my postgresql function.
Up to now I found a solution for this. (Don't know whether this is the optimum solution)
The simple thing to send parameter as string.
With my C# code I make some string like below.
String arr = "array[[5,10,10,10],[30,20,15,16]]";
This arr will be passed as query parameter.
string quy = "pg_sp_getmainrates_11(" + FromCountryId +
"," + ToCountryId +
"," + arr+ ")";
Above solution works fine.
You can use using Newtonsoft.Json; and insert your array like the following:
string[][] arr = {{5, 10, 10, 10},{30, 20, 15, 16}};
var arrayOutput = JsonConvert.SerializeObject(arr);
try
{
string sql1 = "INSERT INTO tbt(img, fcth, dev) VALUES (ARRAY'" + arrayOutput + "')";
dbcmd.CommandText = sql1;
cmd.ExecuteNonQuery();
}
catch (NpgsqlException ex)
{
if (ex.Data == null)
{
throw;
}
else
{
}
}
This example Just for array column.
I'm having a problem inputting variables into my database. I've seen other posts on how to pass a variable through by just escaping it, but those solutions do not apply because I am getting my variable's through an API. I'm cycling though data with a foreach loop by the way.
level = "" + x.Account_Level + "";
name = "" + x.name + "";
command.CommandText = "INSERT INTO `data` (`level`, `name`) VALUES(" + level + ", " + name + ")";
command.ExecuteNonQuery();
Sometimes, a variable will come back with an apostrophe and will screw up the code. Is it possible to insert a slash before every apostrophe or is there a way like in PHP to just push the whole variable through with single quotes? Thanks!
Edit:
Would this work? I think I need to add the i to change the name of the parameter each loop, due to it claiming the parameter as already declared.
using (var web = new WebClient())
{
web.Encoding = System.Text.Encoding.UTF8;
var jsonString = responseFromServer;
var jss = new JavaScriptSerializer();
var MatchesList = jss.Deserialize<List<Matches>>(jsonString);
string connectString = "Server=myServer;Database=myDB;Uid=myUser;Pwd=myPass;";
MySqlConnection connect = new MySqlConnection(connectString);
MySqlCommand command = connect.CreateCommand();
int i = 1;
connect.Open();
foreach (Matches x in MatchesList)
{
command.CommandText = "INSERT INTO `data` (`level`, `name`) VALUES(?level" + i + ", ?name" + i + ")";
command.Parameters.AddWithValue("level" + i, x.Account_Level);
command.Parameters.AddWithValue("mode" + i, x.name);
command.ExecuteNonQuery();
i++;
}
connect.Close();
}
The quick and dirty fix is to use something like:
level = level.Replace("'","whatever");
but there are still problems with that. It won't catch other bad characters and it probably won't even work for edge cases on the apostrophe.
The best solution is to not construct queries that way. Instead, learn how to use parameterised queries so that SQL injection attacks are impossible, and the parameters work no matter what you put in them (within reason, of course).
For example (off the top of my head so may need some debugging):
MySqlCommand cmd = new MySqlCommand(
"insert into data (level, name) values (?lvl, ?nm)", con);
cmd.Parameters.Add(new MySqlParameter("lvl", level));
cmd.Parameters.Add(new MySqlParameter("nm", name));
cmd.ExecuteNonQuery();
in C# project , I have made a datagridview in my form that has some columns.column[0]& column[1] names are fix (day and date) and the other column names are variable and will change by user.these columns have time period thatsis shown with starting and finishing time.
such as from 6 am to 14 pm is shown as 6_14 as columns name.we have a listbox that has variable number of items(counter "i").
///sqlite doesn't accept columns name that start and finish with Numbers.I added word "f" to start and end of each
///column name
string data_str = "";
string data_str2="";
for (int i = 0; i < listBox1.Items.Count;i++ )
{
string temp = "f"+ listBox1.Items[i].ToString()+"f";
data_str = data_str + temp +",";
string temp2 = "#"+listBox1.Items[i].ToString()+",";
data_str2=data_str2+temp2;
}
data_str=data_str.TrimEnd(',');
data_str2=data_str2.TrimEnd(',');
in first step,I made two columns "day" & "date" in data table in my database and imported my data to it successfully.(It works)
string Q_insert = "insert into " + table_name + " (day,date) values (#day,#date)";
SQLiteConnection connect = new SQLiteConnection(connection_string);
SQLiteCommand insert_cmd = new SQLiteCommand(Q_insert, connect);
foreach (DataGridViewRow row in shift_datagrid.Rows)
{
insert_cmd.Parameters.AddWithValue("#day", row.Cells[0].Value.ToString().Trim());
insert_cmd.Parameters.AddWithValue("#date", row.Cells[1].Value.ToString().Trim());
connect.Open();
insert_cmd.ExecuteNonQuery();
connect.Close();
}
in second step,I need to import user data from datagridview to data table but the error takes place.(it doesn't work)
int col_cnt = listBox1.Items.Count;
Q_insert = "insert into " + table_name + " (" + data_str + ") values (" + data_str2 + ")";
connect = new SQLiteConnection(connection_string);
insert_cmd = new SQLiteCommand(Q_insert, connect);
foreach (DataGridViewRow row in shift_datagrid.Rows)
{
string temp1 = "";
for (int i = 0; i < col_cnt; i++)
{
temp1 = "\"#" + listBox1.Items[i].ToString() +"\"";
insert_cmd.Parameters.AddWithValue(temp1, row.Cells[i + 2].Value.ToString().Trim());
}
connect.Open();
insert_cmd.ExecuteNonQuery();
connect.Close();
}
unfortunately, this error occurs:
unknown Error : Insufficient parameters supplied to the command
I googled this error and checked solution ways for same problems but they were not useful for my problem and they couldn't help me anyway.
this is the example of output command strings that insert to data to database (two steps):
1. Insert into [table_name] (day,date) values (#day,#date) -------------->(it works)
2. Insert into [table_name] (f6_14f,f14_22f,f22_6f) values (#6_14,#14_22,#22_6) ------->(it doesn't work)
please help me
thanks
The following may be causing the error:
temp1 = "\"#" + listBox1.Items[i].ToString() +"\"";
insert_cmd.Parameters.AddWithValue(temp1, row.Cells[i + 2].Value.ToString().Trim());
Syntax requires that you don't construct the # as part of the variable value.# is not data. Use it as part of the variable name as you did before like this:
insert_cmd.Parameters.AddWithValue("#Col1",listBox1.Items[i+2].Value.ToString().Trim());
Where #Col1 is a column name of your table.
I don't think you can build the parameter name in a for loop, if so, you have to list the insert statements with each column name parameter prefixed with # as in the above example/code.
i have used a checkbox list in my project .am storing all the checked items values in arraylist using code below
ArrayList services= new ArrayList();
for (int i = 0; i < chkservices.Items.Count; i++)
{
if (chkservices.Items[i].Selected == true)
{
services.Add(chkservices.Items[i].Text+',');
}
}
now the problem is when i insert data in to database instead of data in the arraylist it gets inserted as 'System.Collections.ArrayList' how can i insert all values into database in a single insert statement?
EDIT
inserting into database
con.Open();
SqlCommand cmd = new SqlCommand("insert into XXX(First_Name,Last_Name,ServicesProvided) values ('" + txtfrstname.Text + "','" + txtlastname.Text + "','" + services + "')", con);
cmd.ExecuteNonQuery();
con.Close();
or could anyone provide me a alternative for arraylist..i need to save checked items from checkboxlist and save it in database
it should be saved in database as
First_Name Last_name ServicesProvided
user1firstname user1lastname selectedvalue1,
selectedvalue2,selectedvalue3
Why not to concatenate your data using the following code:
var mydata = String.Join(',', chkservices.Items
.Where( a => a.Selected).Select( b => b.Text));
So you can add your data as a string.
EDIT:
It is a very bad habit of concatenating strings to make a query! Apart from many side effects like in your case here it is a great security breach. Try the parameterized query instead:
SqlCommand cmd = new SqlCommand(
#"insert into XXX(First_Name,Last_Name,ServicesProvided) values
(#First_Name,#Last_Name,#ServicesProvided")", con);
cmd.Parameters.AddWithValue("#ServicesProvided", mydata);
cmd.Parameters.AddWithValue("#First_Name", frstname.Text);
cmd.Parameters.AddWithValue("#Last_Name", txtlastname.Text);
cmd.ExecuteNonQuery();
mydata is the variable from my first example.
You need to get the values of the array list and send them one by one
or create a stored procedure where you send all the values to using Alexanders Galkins example (or use the a Aggregate method). Then use the split function to split up the string and insert all the record
Using INSERT INTO statement you can insert only one row at a time unless you're using sub query to select data from other table.
As you don't have the data in the database, your only option is iterate over the array and insert each value as new row.
Don't use ArrayList, you have generic list for what you need:
List<string> services = new List<string>();
for (int i = 0; i < chkservices.Items.Count; i++)
{
if (chkservices.Items[i].Selected == true)
{
services.Add(chkservices.Items[i].Text);
}
}
//...connection stuff....
strSQL = "INSERT INTO MyTable (MyField) VALUES (#val)"
using (SqlCommand command = new SqlCommand(strSQL, connection))
{
command.Parameters.AddWithValue("#val", "");
foreach (string service in services)
{
command.Parameters["#val"].Value = service;
command.ExecuteNonQuery();
}
}
How many checkbox do you have? If you just have a little checkbox, so I suggest you transform each state of them into bit mask which represent a number, then store it to database.
long bitMask = 0; // All uncheck
for (int i = 0; i < chkServices.Items.Count; ++i) {
if (chkServices.Items[i].Checked) {
bitMask |= (1 << i);
}
}
// Store bitMask to Database
In later, you can get state via bitMask again when needed.