First off I'd like to apologize if this is more of a question than an example but I'm really lost here. I have a Windows Form that loads info from a text file. In each text file there is all the cities and counties in a given state, each section is separated by the .Split. I have a SQL Server 2008 database, 2 columns, Name and type. What I'd like to do is take all of the information and add it too individual rows with the name column being the name and the type column being state or county. Here is how I have the information split. How would I add a new row for each entry in the text?
void PopulateZones()
{
ofdFile.Filter = "Text File (.txt)|*.txt|All Files (*.*|*.*";
ofdFile.FilterIndex = 1;
ofdFile.Multiselect = true;
ofdFile.FileName = String.Empty;
if (ofdFile.ShowDialog() == DialogResult.OK)
{
ofdFileLocTextBox.Text = ofdFile.FileName.ToString();
string groups = File.ReadAllText(ofdFile.FileName);
string[] parts = groups.Split(new char[] { '*' }, StringSplitOptions.RemoveEmptyEntries);
stateTextBox.Text = parts[0];
citiesTextBox.Text = parts[1];
countiesTextBox.Text = parts[2];
AddtoSQL(parts[0], parts[1]);
}
}
void AddtoSQL(string cities, string counties)
{
Sqlconnection conn = new SqlConnection(connString)
Sqlcommand comm = new Sqlcommand("INSERT into [Table] (Name, Type) Values (#Name, #Type))";
comm.Parameters.Add(#Name, each line of textbox);
comm.Parameters.Add(#Type, City or County);
comm.ExecuteNonQuery();
}
So, the first problem you have is that your code is not doing what you think it does.The big problem is that you are reading in all the text and then only ever selecting the first three values of it.You don't give the format of your data, but suppose it looks like this:
Scotland*Edinburgh*Midlothian*
Scotland*Perth*Perthshire*
Your code
string groups = File.ReadAllText(ofdFile.FileName);
Reads the whole file into one string, such that it will look like this
Scotland*Edinburgh*Midlothian*\r\nScotland*Perth*Perthshire*
So splitting it using the following
string[] parts = groups.Split(new char[] { '*' },
StringSplitOptions.RemoveEmptyEntries);
gives you a string array of 6 parts. Inserting multiple lines from this is doable but won't be very neat. You'd be much better to read your text files in by lines, and then iterate over the array of lines, splitting each one as you go and then adding the relevant parts to SQL. Something like
string[] lines = System.IO.File.ReadAllLines(ofdFile.FileName);
foreach (var line in lines)
{
string[] parts = line.Split('*');
AddtoSQL(parts[0], parts[1]);
}
That should insert all the data, but as an aside, if you are looking to execute numerous inserts at once, I'd recommend housing those inserts inside of a SQL Transaction.
I'd direct you to have a look at this MSDN article on the SqlTransaction Class
The gist of it is that you declare a transaction first, then loop over your inserts executing those against the transaction. Finally, when you commit your transaction the queries are all written to the database en mass. The reason I'd do this is that it will be much quicker and safer.
Does it work if you change your sql statement into "insert into [table] (name, type) values(#name, #type)"? with the bracket.
In SQL Server 2008 you can insert multiple line (records) with one query. All you need to do is a loop to extract row values and construct query string. So in AddToSQL method make your query like:
INSERT INTO [Table](Name, Type)
VALUES ('First',State1),
('Second',State2),
('Third',State3),
('Fourth',State4),
Insert Multiple Records Using One Insert Statement
Related
I want to insert data into table using SP. But I have database table column name in parameters. I want to use parameters as column in SP to insert data. You have any idea to insert data through column name as parameter.
cmd3.Connection = conn;
cmd3.CommandType = CommandType.StoredProcedure;
cmd3.CommandText = "CustomerInfoProcedure";
cmd2.Parameters.AddWithValue("#Col0", Col0);
cmd2.Parameters.AddWithValue("#Col1", Col1);
cmd2.Parameters.AddWithValue("#Col2", Col2);
//insert query using in SP, but its give error
insert into #AgentDetails (#Col0, #Col1, #Col2)
values (#eCol0, #eCol1, #eCol2);
To my knowledge (although I haven't worked with SQL Server for a while) you can't really do that directly. If you insist on having it this way, you have a couple of (bad) options:
Use sp_executesql and build your query dynamically by concatenating relevant strings (MSDN). This approach will likely result in fairly slow queries (since they can't be optimized before they are generated) and has huge security downsides (think SQL injection).
Have a set of prepared queries inside your SP that cover all possible combinations of the input parameters. This will alleviate performance and security concerns, but it will leave you (depending on the number of field combinations you want to have) with a huge and complicated code in your SP that will be hard to maintain.
UPD:
After seeing your comment: in your case it will be much better to handle column reordering in the code and only have a single signature for the SP. E.g.
var value0 = Col0 == "field0" ? eCol0 : Col1 == "field0" ? eCol1 : eCol2;
var value1 = ...
cmd3.Connection = conn;
cmd3.CommandType = CommandType.StoredProcedure;
cmd3.CommandText = "CustomerInfoProcedure";
cmd2.Parameters.AddWithValue("#value0", value0);
cmd2.Parameters.AddWithValue("#value1", value1);
cmd2.Parameters.AddWithValue("#value2", value2);
//insert query using in SP
insert into #AgentDetails (field0, field1, field2)
values (#value0, #value1, #value2);
UPD2
If you have a large number of variables, then similar approach would work as long as all the values and column-field mapping are stored in appropriate data structures. E.g. let's say that you have an array of column names in the order they follow in your spreadsheet, e.g. taken from a spreadsheet header:
string[] columnsNames; // ["field1", "field2", "field10", "field0", ...]
, an array of values that you need to insert, per row, at the same order as the columnsNames:
string[] values; // ["value1", "value2", "value10", "value0", ...]
and an array where the column names are listed in the order they need to be in for your SP parameters:
// This list can be made into a constant, but you need
// to keep it in sync with the SP signature
string[] parameterOrder = ["field0", "field1", "field2", ...];
In this case you can use logic like this one to add your data right into the correct place:
// This dictionary will be used for field position lookups
var columnOrderDict = new Dictionary<string, int>();
for (var i = 0; i < columnsNames.Length; i++)
{
columnOrderDict[columnsNames[i]] = i;
}
cmd3.Connection = conn;
cmd3.CommandType = CommandType.StoredProcedure;
cmd3.CommandText = "CustomerInfoProcedure";
for (var j = 0; j < parameterOrder.Length; j++)
{
var currentFieldName = parameterOrder[j];
if (columnOrderDict.ContainsKey(currentFieldName))
{
cmd3.Parameters.AddWithValue(currentFieldName, values[columnOrderDict[currentFieldname]]);
} else {
cmd3.Parameters.AddWithValue(currentFieldName, DBNull.Value);
}
}
This code is built on multiple assumptions, such as that the column headers in your spreadsheet will exactly match the stored procedure parameter names etc, but I hope it should give you enough of a hint to build your own logic.
Also don't forget proper validation - currently the only thing this code guards against is the situation when a field that's needed by SP is missing from the input data. You also need to validate data format, the number of values should match the number of headers etc. etc.
I am executing a SQL Server stored procedure from my C# code which essentially pulls some data from a database based on the supplied condition.
DataSet GetAllxxxxxByDate(string entityValue,string companyValue)
{
using (var sqlConn = new SqlConnection(GetConnectionString()))
{
using (var cmd = new SqlCommand())
{
var data = new DataSet();
cmd.CommandText = “myStoredprodecure”;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = sqlConn;
var eVal = string.IsNullOrWhiteSpace(entityValue) ? string.Empty : entityValue;
cmd.Parameters.AddWithValue("#entity_value", eVal);
var company = string.IsNullOrWhiteSpace(companyValue) ? string.Empty : companyValue;
cmd.Parameters.AddWithValue("#company", company);
var sqlDataAdaptor = new SqlDataAdapter(cmd);
sqlDataAdaptor.Fill(data);
return data;
}
}
}
Here entityValue, companyValue are comma separated strings, formed dynamically within C# code and pass it to stored procedure.
Eg:
’first’,’second’,’third’
And the stored procedure uses these values to fill the NOT IN condition defined within it.
The issue is that, I am getting inconsistent number of records when I execute the code.
Following is a quick screenshot where first WHERE clause return 3 records and second WHERE clause return 1 record. The input values for the first WHERE clause is been filled from c# code and the second is been filled manually to test.
The only difference, which I can spot is number of quotes.
Question: can someone help me to zero in the issue or the difference in these give WHERE clause ?
Well, you don't show what entity_value is in your results, but the difference between the two is you're adding single quotes around the literal values:
N'''FSEC''' in SQL is the literal valiue 'FSEC'
'FSEC' in SQL is just FSEC (without the quotes).
My guess is that records 2004981 and 2004982 have a value of FSEC (without the quotes) for entity_value.
If you're adding parameter values from C# code, don't add quotes around them like you would if you were building a string. SQL will treat the values as strings without needing string qualifiers.
EDIT
Okay, I just read this statement:
Here entityValue, companyValue are comma separated string
You can't just pass in a comma-delimited string to an IN clause. To search for multiple values there are a few options:
Add commas to each end and use LIKE:
Where (',' + #entity_value +',' LIKE '%,' + entity_value + ',%')
Parse the string into a temporary table, than use that table in your IN clause
Pass the values as a table-valued parameter and use that in your IN clause.
Build the SQL statement as a string and execute it with EXEC
I want to retrieve a score of words from databse and then I will make a decision about paragraph that this is positive paragraph or negative paragraph
The database file format is like this. where some key word have positive and negative score
Word Pos_Score Neg_Score
Able .324 .834
Country .987 .213
Love .378 .734
agree .546 .123
industry .289 .714
guests .874 .471
The Paragraph will be like this.
I agree with you. It seems an intelligent tourist industry allows its guests to either immerse fully, in part, or not, depending upon the guest. That is why the ugly American charges have always confused me.
Now I will compare each word of the paragraph with database file if the word found in the database file then I will retrieve the Pos_Scoe and Neg_Score score of word and these score will be store in variable when the whole paragraph will compare at the end Pos_Score will add separately and the Neg_Score will add separately . and this will be the result.
Code that i try is this
private void button1_Click(object sender, EventArgs e)
{
string MyConString = "server=localhost;" +
"database=sentiwornet;" + "password=zia;" +
"User Id=root;";
MySqlConnection connection = new MySqlConnection(MyConString);
MySqlCommand command = connection.CreateCommand();
MySqlDataReader Reader;
StreamReader reader = new StreamReader("D:\\input.txt");
string line;
while ((line = reader.ReadLine()) != null)
{
string[] parts = line.Split(' ');
foreach (string part in parts)
{
command.CommandText = "SELECT Pos_Score FROM score WHERE Word = 'part'";
command.CommandText = "SELECT Neg_Score FROM score WHERE Word = 'part'";
//var
connection.Open();
Reader = command.ExecuteReader();
}
}
}
First, this query promises to be horribly inefficient. Instead, if your paragraphs are small enough, I would execute all of the joins inside the database by passing in the arguments as a CSV-list, then converting to a table in SQL. The following function will do that (courtesy of http://codebank.wordpress.com/2007/03/06/simple-sql-csv-to-table-2/):
Caveat: you will need to strip all punctuation out using something like string.Replace(new[] { '.', ',' ... etc })
Also, it's possible that my code doesn't do exactly what you want - it may not even compile - but that is the joy of programming. This gives you the general idea I have on how to solve a rather complex problem.
Edit: I just realized you are using MySql. This code would work for MSSQL - I have never used MySql from the CLR, so I don't know if all of the classes are equivalent. You may need to go back to what you were doing before.
CSV to List
Create Function dbo.fn_CSVToTable (#CSVList Varchar(MAX))
Returns #Table Table (ColumnData Varchar(50))
As
Begin
If right(#CSVList, 1) <> ','
Select #CSVList = #CSVList + ','
Declare #Pos Smallint,
#OldPos Smallint
Select #Pos = 1,
#OldPos = 1
While #Pos < Len(#CSVList)
Begin
Select #Pos = CharIndex(',', #CSVList, #OldPos)
Insert into #Table
Select LTrim(RTrim(SubString(#CSVList, #OldPos, #Pos - #OldPos))) Col001
Select #OldPos = #Pos + 1
End
Return
End
SQL Procedure
CREATE PROCEDURE dbo.spGetWordScores (#csv varchar(MAX))
AS
select POS_SCORE, NEG_SCORE, WORD from score
inner join dbo.fn_CSVToTable(#csv) input
on input.ColumnData = score.WORD
New C# Code
var MyConString = "server=localhost;" +
"database=sentiwornet;" + "password=zia;" +
"User Id=root;";
var connection = new MySqlConnection(MyConString);
//Each line in the array will probably be one paragraph.
var fileLines = File.ReadAllLines("D:\\input.txt");
foreach (var line in fileLines)
{
//Format your line into words by removing punctuation. I'm not going to bother
//with that code because it is trivial.
//var csv = line.Split(' ');
var command = connection.CreateCommand();
command.CommandText = "exec spGetWordScores";
command.Parameters.AddWithValue("#csv", csv);
var ds = command.ExecuteDataSet();
//Now you have a DataSet with your word scores. do with them what you will.
}
Helpful Extension Method
public static class Extensions
{
public static DataSet ExecuteDataSet(this SqlCommand command)
{
using (SqlDataAdapter da = new SqlDataAdapter(command)) {
DataSet ds = new DataSet();
// Fill the DataSet using default values for DataTable names, etc
da.Fill(ds);
return ds;
}
}
}
Going back and forward to the database is going to kill your performance. Best to write a stored procedure that takes in your input string, splits it and calculates the score - this way all of the processing will happen on one machine and you will save significant time by not communicating partial results.
I have this program that is feeding me data. I take this data (string) and parse it so that the different fields can go into the respective db table column. I can parse the string but I can't find the right function or way to send them to the db. This is my second time working with sql server or database in general. I have done inserts this way
MyCommand.CommandType = System.Data.CommandType.Text;
MyCommand.CommandText = "INSERT INTO TimeStampTable(ID, TimeStamp) VALUES ('24', 'sep 13, 2009')";
From what I know, CommandType only allows either text or a stored procedure. In this case, I would want to insert the string that is being parsed.
string teststring = dtString;
string[] result = teststring.Split(',', ' ', ':', '=');
Console.WriteLine("The parsed string looks like this:");
foreach (string word in result)
{
Console.WriteLine(word);
}
This is my code that parses my incoming string. So I receive name address zip state, etc. I would like for name to go to col1, address to go to col2, etc. I think the ideal way to do this would be to convert my loop to something like this
foreach (string word in result)
{
SqlDatasource.InsertCommand=Insert into Tablename col1 col2 col3(word);
}
Does anyone have any suggestions?
I will answer your question directly, but there are many different ways that you could go about performing the same thing (I will list some at the end)
String insertQuery = "INSERT INTO TABLENAME (Col1, Col2, Col3...) VALUES (";
//This is also assuming that your data is in the same order as the columns
int isFirstLoop = true
foreach(string word in result)
{
if(!isFirstLoop)
insertQuery += ","
insertQuery += word;
isFirstLoop = false;
}
insertQuery += ")";
SqlDataSource.InsertCommand = insertQuery;
NOTE: this is very open to SQL Injection, so keep that in mind (do you trust your incoming source). There are ways to clean the data, but ultimately, I suggest some of the methods listed below
Alternatives:
Use a stored procedure over direct TSQL. Then you can map your data to SQLParameters, which (I believe) are built to scrub the data to protect against SQL Injection
Use a very basic ORM and/or LINQ so that you can work with objects directly. Then you only need to read the data into a POCO
I am sure there are other ways, however for some reason I am drawing a blank. I think that is because these are the most used alternatives :)
In my project i have to give a string input through a text field, and i have to fill a database table with these values. I should first check the values of a specific table column, and add the input string only if it is not there in the table already.
I tried to convert the table values to a string array, but it wasn,t possible.
If anyone have an idea about this, your reply will be really valuable.
Thankx in advance.
Since you say your strings in the database table must be unique, just put a unique index on that field and let the database handle the problem.
CREATE UNIQUE INDEX UIX_YourTableName_YourFieldName
ON dbo.YourTableName(YourFieldName)
Whenever you will try to insert another row with the same string, SQL Server (or any other decent RDBMS) will throw an exception and not insert the value. Problem solved.
If you need to handle the error on the front-end GUI already, you'll need to load the existing entries from your database, using whatever technology you're familiar with, e.g. in ADO.NET (C#, SQL Server) you could do something like:
public List<string> FindExistingValues()
{
List<string> results = new List<string>();
string getStringsCmd = "SELECT (YourFieldName) FROM dbo.YourTableName";
using(SqlConnection _con = new SqlConnection("your connection string here"))
using(SqlCommand _cmd = new SqlCommand(getStringsCmd, _con)
{
_con.Open();
using(SqlDataReader rdr = _con.ExecuteReader())
{
while(rdr.Read())
{
results.Add(rdr.GetString(0));
}
rdr.Close();
}
_con.Close();
}
return results;
}
You would get back a List<string> from that method and then you could check in your UI whether a given string already exists in the list:
List<string> existing = FindExistingValues();
if(!existing.Contains(yournewstring))
{
// store the new value to the database
}
Or third option: you could write a stored procedure that will handle the storing of your new string. Inside it, first check to see whether the string already exists in the database
IF NOT EXISTS(SELECT * FROM dbo.YourTableName WHERE YourFieldName = '(your new string)')
INSERT INTO dbo.YourTableName(YourFieldName) VALUES(your-new-string-here)
and if not, insert it - you'll just need to find a strategy how to deal with the cases where the new string being passed in did indeed already exist (ignore it, or report back an error of some sorts).
Lots of options - up to you which one works best in your scenario!