I have dynamically generated text-box for which i need to write an insert query into my SQL server 2005 database.
The problem is when i write the insert query i can't include the text-box names as the text-box will be generated run time.
I tried using the following logic:
PLEASE NOTE THAT I WISH TO GENERATE DYNAMIC TEXTBOXES AND THEN A DYNAMIC SQL QUERY.
String str=//will contain a data fetched from all the textboxes generated dynamically and will be seprated using a ','(as in an insert statement).
This string str will be directly passed on to the insert query so that all the values will be taken in directly.
But the logic does not work.
Please help..
A couple of points
Your method leaves you open to SQL injection attacks. This is a bad thing. You should use a sqlCommand object to execute the SQL, using parameter objects to pass in the values to insert, this will guard against SQL Injection attacks.
Name your textboxes after each column in the table your inserting into.
Hope this helps
You need to keep track of your text boxes as they are generated.
List<TextBox> TextBoxes = new List<TextBox>();
...
TextBox DynamicBox1 = new TextBox();
...
TextBoxes.Add(DynamicBox1);
Then if you have the names of your columns somewhere
string Columns = "#col0, #col1, #col2"; //etc
string Query = #"INSERT INTO [Table]
(" + Columns.Replace("#", "") + ")
VALUES (" + Columns+ ")";
using a paramaterized command
SqlCommand Command = new SqlCommand(Query, Connection);
for (int i=0; i<TextBoxes.Count; i++)
{
Command.Parameters.AddWithValue("#col" + i, TextBoxes[i].Text);
}
Connection.Open()
Command.ExecuteNonQuery();
Connection.Close()
I have not added in error handling
Related
I have been asked to look at finding the most efficient way to take a DataTable input and write it to a SQL Server table using C#. The snag is that the solution must use ODBC Connections throughout, this rules out sqlBulkCopy. The solution must also work on all SQL Server versions back to SQL Server 2008 R2.
I am thinking that the best approach would be to use batch inserts of 1000 rows at a time using the following SQL syntax:
INSERT INTO dbo.Table1(Field1, Field2)
SELECT Value1, Value2
UNION
SELECT Value1, Value2
I have already written the code the check if a table corresponding to the DataTable input already exists on the SQL Server and to create one if it doesn't.
I have also written the code to create the INSERT statement itself. What I am struggling with is how to dynamically build the SELECT statements from the rows in the data table. How can I access the values in the rows to build my SELECT statement? I think I will also need to check the data type of each column in order to determine whether the values need to be enclosed in single quotes (') or not.
Here is my current code:
public bool CopyDataTable(DataTable sourceTable, OdbcConnection targetConn, string targetTable)
{
OdbcTransaction tran = null;
string[] selectStatement = new string[sourceTable.Rows.Count];
// Check if targetTable exists, create it if it doesn't
if (!TableExists(targetConn, targetTable))
{
bool created = CreateTableFromDataTable(targetConn, sourceTable);
if (!created)
return false;
}
try
{
// Prepare insert statement based on sourceTable
string insertStatement = string.Format("INSERT INTO [dbo].[{0}] (", targetTable);
foreach (DataColumn dataColumn in sourceTable.Columns)
{
insertStatement += dataColumn + ",";
}
insertStatement += insertStatement.TrimEnd(',') + ") ";
// Open connection to target db
using (targetConn)
{
if (targetConn.State != ConnectionState.Open)
targetConn.Open();
tran = targetConn.BeginTransaction();
for (int i = 0; i < sourceTable.Rows.Count; i++)
{
DataRow row = sourceTable.Rows[i];
// Need to iterate through columns in row, getting values and data types and building a SELECT statement
selectStatement[i] = "SELECT ";
}
insertStatement += string.Join(" UNION ", selectStatement);
using (OdbcCommand cmd = new OdbcCommand(insertStatement, targetConn, tran))
{
cmd.ExecuteNonQuery();
}
tran.Commit();
return true;
}
}
catch
{
tran.Rollback();
return false;
}
}
Any advice would be much appreciated. Also if there is a simpler approach than the one I am suggesting then any details of that would be great.
Ok since we cannot use stored procedures or Bulk Copy ; when I modelled the various approaches a couple of years ago, the key determinant to performance was the number of calls to the server. So batching a set of MERGE or INSERT statements into a single call separated by semi-colons was found to be the fastest method. I ended up batching my SQL statements. I think the max size of a SQL statement was 32k so I chopped up my batch into units of that size.
(Note - use StringBuilder instead of concatenating strings manually - it has a beneficial effect on performance)
Psuedo-code
string sqlStatement = "INSERT INTO Tab1 VALUES {0},{1},{2}";
StringBuilder sqlBatch = new StringBuilder();
foreach(DataRow row in myDataTable)
{
sqlBatch.AppendLine(string.Format(sqlStatement, row["Field1"], row["Field2"], row["Field3"]));
sqlBatch.Append(";");
}
myOdbcConnection.ExecuteSql(sqlBatch.ToString());
You need to deal with batch size complications, and formatting of the correct field data types in the string-replace step, but otherwise this will be the best performance.
Marked solution of PhillipH is open for several mistakes and SQL injection.
Normally you should build a DbCommand with parameters and execute this instead of executing a self build SQL statement.
The CommandText must be "INSERT INTO Tab1 VALUES ?,?,?" for ODBC and OLEDB, SqlClient needs named parameters ("#<Name>").
Parameters should be added with the dimensions of underlaying column.
I get an error when I try to insert a double value into a table in MySQL.
I use C# to build my transactions, and ODBC drivers to connect my database to my project.
In my aspx page I make a form which permit to the user to fill severals fields and submit the values. By an Ajax call, I go in my code behind sending the form's values. And i begin my transaction.
If the user puts for instance "15.00" in the form for the double
values, the resquest is Ok and there is not problems.
But if he puts "15.65" I get an error which says that the column
count of my table doesn't match with the request column count.
However, I check the double value and it is correct. I also try to put simple quotes next to the double value, but it doesn't work.
Here is the error :
`{"Message":"[MySQL][ODBC 5.1 Driver][mysqld-5.1.73-community]Column count doesn\u0027t match value count
at row 1","StackTrace":" à ADODB.ConnectionClass.Execute(String CommandText, Object& RecordsAffected
, Int32 Options)\r\n...
Here is my resquest :
Utils.ocn.Execute("INSERT INTO datas VALUES(0,null,null,null,null,null," + RecepAccId + ",1," + CafId + ",123,null,null," + NbrKilos + ",'" + ConvertedDate + "','" + Chrono + "','" + ConvertedTimeStamp + "','" + ChronoNum + "')", out x, -1);
The severals variables provening my function's parameters
There are 17 fields in my table and I send normally 17 values in my resquests. But when I set the double with numbers after the comma, I get a bug. And according to the error message, we can suppose that, the numbers after the comma are considerated like a other field in the insert !
In doubt I put the 17 fields'names after the table name in my resquest, but I get the same result.
Have you an idea to fix it ?
To get your database driver to treat the values from the user input as individual pieces of data, you should use a parametrised query. So if your table had a single double column called, height for example.
INSERT INTO datas height
VALUES #height
Where #height is a double value parsed from the input from the request eg using double parsedHeight = double.Parse(subbmittedValue). You can then add the parameter when making your SQL command by adding:
command.Parameters.AddWithValue("#height", parsedHeight);
As #Marko Juvančič says, using string concatenation from user input to create a sql statement is dangerous. In fact, it is a major security issue leaving you open to SQL injection. Imagine a malicious user entered a SQL query to delete datas in the form. Parametrising your query as described protects you from this by preventing the user from interfering with your query.
So putting all this together, instead of executing your concatenated statement with Utils.ocn.Execute use something like:
double parsedValue = double.Parse(valueFromRequest);
//be careful, this will throw if the user didn't enter a valid double.
string connectionString = yourConnectionString;
using (OdbcConnection connection = new OdbcConnection(connectionString))
{
connection.Open();
using (OdbcCommand command = new OdbcCommand(
"INSERT INTO datas columnName VALUES(#value)", connection))
{
command.Parameters.AddWithValue("#value", parsedValue);
command.ExecuteNonQuery();
}
}
private double failingGrade;
public double getFailingGrade()
{
using (MySqlConnection conn = new MySqlConnection(DBConnection.Connection()))
{
conn.Open();
using (MySqlCommand comm = conn.CreateCommand())
{
comm.CommandText = "select failing from gradespercentage_tab";
return failingGrade = double.Parse(comm.ExecuteScalar().ToString());
}
}
}
I have a problem in button1 click event of inserting data into a table which table name be determined by whatever text is in textbox1
Should mean something like that:
tablename = textbox1.text;
sql = "INSERT INTO tablename ([itemserial], [itemname], [itemcount],[itemimage]) VALUES (#itemserial, #itemname, #itemcount, #itemimage)";
Having a textbox containing the name of your table is challenging because you should add extra care in handling this value. You should implement some kind of checking on this textbox value. A possible solution is to check against your database schema if the table typed by your user really exists.
You don't tell us which database system are you using so I will show an example using Sql Server
string tableName = textbox1.text;
using(SqlConnection cnn = new SqlConnection(... connectionstring...))
{
cnn.Open();
DataTable dt = cnn.GetSchema("TABLES");
DataRow[] rows = dt.Select("TABLE_NAME = '" + tableName + "'");
if(rows.Length > 0)
{
// Now you are sure to have a valid table in your textbox
// and could use the input value without risking an Sql Injection
string sql = "INSERT INTO [" + tableName + "] ([itemserial]," +
"[itemname],[itemcount],[itemimage]) " +
"VALUES(#itemserial,#itemname,#itemcount,#itemimage)";
.... the remainder of your code that use the query above....
}
else
MessageBox.Show("Please enter a valid name for your table");
Extending this approach you could change your TextBox to a ComboBox with ComboBoxStyle set to DropDownList (to block typing) and fill the ComboBox with the names returned by the GetSchema call above....
tablename = textbox1.text;
sql = string.Format("INSERT INTO {0} ([itemserial],[itemname],[itemcount],[itemimage])VALUES(#itemserial,#itemname,#itemcount,#itemimage)", tablename);
Although I would strongly recommend against this as it allows people to enter whatever they want into that textbox. Something like:
Robert; DROP TABLE Students;--
Which is discussed in more detail here:
How does the SQL injection from the "Bobby Tables" XKCD comic work?
Change your query like this
sql = "INSERT INTO "+tablename+" ([itemserial],[itemname],[itemcount],[itemimage]) VALUES (#itemserial,#itemname,#itemcount,#itemimage)";
I want to attach a DataSet with parameterized query. Something like a user entering a value in a text box then hit submit button.
I have created a Text Field and a click button event something like :
private void Btn_GetProjDetails_Click(object sender, EventArgs e)
{
string userEnteredProjId = tab3ProjIdInput.Text;
}
but now don't know how to use this userEnteredProjId variable in my query?
I haven't tried the manually coding all the data-connections path. Instead added the GUI in VS2012 to add a data source. Then using this data source I have learned we can add datasets, and then use these DataSets to just drag and drop in our form. So I created a dataset and then dataset toolbox, I added my table and created a query but don't know how to use the userEnteredProjId in my query here.
You never want to just insert a value from a user into an SQL query because that is a huge SQL injection risk. It is better to use parameters, and better still if you do some validation on the parameters before using them. Here is a basic example of using a command parameter.
using (cmd command = new SqlCommand())
{
string sql = "Select * from table where projid=#UserEnteredProjid";
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("UserEnteredProjid", your_value_here);
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
//do something;
}
}
Well, your query is just a string variable I'm guessing, like "select * from table". You just want to take some user entered data to augment your query:
string query = "select * from table where projid = " + UserEnteredProjid;
I need to programmatically create a SQL Server 2008 table in C# such that the columns of the table should be generated from a list of columns (each column name is the name of a row in the table)
My question is what is the command string to loop through the list of columns and creates the table's recorded:
List<string> columnsName = ["col1","col2","col3"]
I want to create a table with the columns in the columnsName. But since the list size in not constant, I need to loop through the list to generate the table columns.
The simple answer is
CREATE TABLE table_name
(
column_name1 data_type,
column_name2 data_type,
column_name3 data_type,
....
)
from w3Schools.com
In C# use a string builder to concatenate the query and then execute the query.
StringBuilder query = new StringBuilder();
query.Append("CREATE TABLE ");
query.Append(tableName);
query.Append(" ( ");
for (int i = 0; i < columnNames.Length; i++)
{
query.Append(columnNames[i]);
query.Append(" ");
query.Append(columnTypes[i]);
query.Append(", ");
}
if (columnNames.Length > 1) { query.Length -= 2; } //Remove trailing ", "
query.Append(")");
SqlCommand sqlQuery = new SqlCommand(query.ToString(), sqlConn);
SqlDataReader reader = sqlQuery.ExecuteReader();
Note: tableName, columnNames, and columnTypes would be replaced with what ever you are getting the data from. From your description it sounds like you are getting the column values from a query, so rather than using a for loop and arrays you will probably be using a while loop to iterate through the results to build the query. Let me know if you need an example using this method and I will make one tonight.
If you are having trouble with the syntax for creating the table you can try creating the table (or a sample table) in MS SQL Server Management Studio, then right click the table and select Script Table as\Create To\New Query Editor Window. This will show you the script it would use to build the query.
Are you looking to implement something like an Entity–attribute–value model?
http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model