My query is giving one result only i.e. one word for one URL when it should run for every entry in dt. Here dt is DataTable and contains many rows, url_given is a String. temp is table containing the words to be matched. Can anybody please tell me what is wrong with my query?
wordcount is the name of the table. url_String, word and count are columns.
The purpose of the query is to get the URLs matched with given URL and
their words which are in the list which is temp.
foreach (DataRow row in dt.Rows)
{
// read item
url_given = row["url_String"].ToString();
String qrystring = "select url_String,word,count from wordcount where url_String='" + url_given + "' and word in (select * from temp) ";
dt1 = db.searchandorder(qrystring);
// searchandorder is a call to a function that establishes the db connections and passes the query to the data adapter.
}
Here is my searchandorder function:
public DataTable searchandorder (String sql)
{
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(sql, conn);
DataSet ds = new DataSet();
DataTable dt = new DataTable();
da.Fill( dt);
conn.Close();
Console.Write("table coloumns" + dt.Columns.ToString());
return dt;
}
Your problem comes from the fact you loop overwriting dt1 every time. You need to merge the results not replace them, but I can't say how you would do that without seeing db.searchandorder.
Also you have a very dangerous sql injection attack. If url_given was '; drop table wordcount; -- what would be the query the program will execute on the server? You need to use parameters with your data adapter.
EDIT: So, now that you shown your code, here is how you fix it. Instead of making a new DataTable every single time you pass you make one outside of the loop and pass in the same table every time. TableAdapter does not clear out the table before it fills by default.
private YourFunction(DataTable dt)
{
DataTable dt1 = new DataTable();
foreach (DataRow row in dt.Rows)
{
// read item
url_given = row["url_String"].ToString();
String qrystring = "select url_String,word,count from wordcount where url_String='" + url_given + "' and word in (select * from temp) ";
db.searchandorder(qrystring, dt1);
// searchandorder is a call to a function that establishes the db connections and passes the query to the data adapter.
}
DoSomthingWithResults(dt1);
}
public void searchandorder (String sql, DataTable dt)
{
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(sql, conn);
da.Fill( dt);
conn.Close();
Console.Write("table coloumns" + dt.Columns.ToString());
return dt;
}
Now, that is the bare minimum to make your program work. There are a LOT of other bad practices you are doing.
Don't reuse a connection: Your conn object should be created inside searchandorder and be inside a using statement. Don't worry about making "too many connection", .NET will use connection pooling and reuse old connections.
Use using statments: Anything that implements IDisposable should be in a using statement (unless the item is being returned)
Follow naming standards: There is a set of standards C# code follows, your class searcandhorder should be named SerchAndOrder.
Use Parameters: You are vulnerable to a SQL injection attack use parameters for your data adapters. Not only does it improve safety, it makes your program faster by allowing SQL server to cache the query execution plan.
Here is a version of your program with those fixes applied.
private YourFunction(DataTable dt)
{
DataTable dt1 = new DataTable();
foreach (DataRow row in dt.Rows)
{
// read item
url_given = row["url_String"].ToString();
var parameter = new SqlParameter("#urlGiven", SqlDbType.VarChar, url_given.Length);
parameter.Value = url_given;
String qrystring = "select url_String,word,count from wordcount where url_String=#urlGiven and word in (select * from temp) ";
db.searchandorder(qrystring, dt1, parameter);
// searchandorder is a call to a function that establishes the db connections and passes the query to the data adapter.
}
DoSomthingWithResults(dt1);
}
public void SearchAndOrder (String sql, DataTable dt, params SqlParameter[] parameters)
{
using(var conn = new SqlConnection(_connectionString))
using(var da = new SqlDataAdapter(sql, conn))
{
da.SelectCommand.Parameters.AddRange(parameters);
conn.Open();
da.Fill(dt);
}
Console.Write("table coloumns" + dt.Columns.ToString());
return dt;
}
Related
I created a Windows Forms application in C# and my database in Visual Studio. I want to know how, if it's possible, to sort one of the columns in the table by clicking a button? Or how can I sort this column automatically without using a button?
I've tried to implement this sort in the code below, but it doesn't work :(
private c void button5_Click(object sender, EventArgs e)
{
SqlConnection sqlConnection = new SqlConnection("Here is my connecting string");
SqlCommand myCommand = new SqlCommand("SELECT * FROM [Information] ORDER BY (Перевозчик)", sqlConnection);
sqlConnection.Open();
myCommand.ExecuteNonQuery();
}
As found here: https://www.w3schools.com/sql/sql_orderby.asp
Sine we don't know what you want to oder we can only guess here.
But with the query you could try:
SELECT column1, column2, ...
FROM table_name
ORDER BY column1, column2, ... ASC
In your case:
"SELECT * FROM [Information] ORDER BY (Перевозчик) ASC"
Best would be to use the visual query builder where you can query against your database. When you are happy with your result you can at least be sure that the query is correct.
How you can do that is explained here:
https://www.c-sharpcorner.com/article/connect-to-a-database-from-visual-studio/
Since the sqlconnection and the sqlcommand is disposable you should consider putting it in a using tag, like in this example.
https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand?view=netframework-4.8
private static void ReadOrderData(string connectionString)
{
string queryString =
"SELECT OrderID, CustomerID FROM dbo.Orders;";
using (SqlConnection connection = new SqlConnection(
connectionString))
{
SqlCommand command = new SqlCommand(
queryString, connection);
connection.Open();
using(SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}",
reader[0], reader[1]));
}
}
}
}
There is 2 way for sort data
1) sorting just data and fill into grid:
DataGridView datagridview1 = new DataGridView(); // for show data
DataTable dt1 = new DataTable(); // have data
DataTable dt2 = new DataTable(); // temp data table
DataRow[] dra = dt1.Select("", "ID DESC");
if (dra.Length > 0)
dt2 = dra.CopyToDataTable();
datagridview1.DataSource = dt2;
2) sort default view that is like of sort with grid column header:
DataGridView datagridview1 = new DataGridView(); // for show data
DataTable dt1 = new DataTable(); // have data
dt1.DefaultView.Sort = "ID DESC";
datagridview1.DataSource = dt1;
I found this solution here:
Sorting rows in a data table
For a listbox you could give this a shot
ArrayList q = new ArrayList();
foreach (object o in listBox4.Items)
q.Add(o);
}
q.Sort();
listBox5.Items.Clear();
foreach(object o in q){
listBox5.Items.Add(o);
}
I found this solution here:
Sorting a list of items in a list box
You need to do ExecuteDatareader then process the result coming from this call. ExecuteNonQuery cannot be used to retrieve data.
I am trying to get column names for particular data table.
I tried with this code.
datagridFieldCreation.AutoGenerateColumns = false;
DataTable dt = new DataTable();
SqlDataAdapter sda = new SqlDataAdapter("select * from Add_Information ", con);
sda.Fill(dt);
datagridFieldCreation.DataSource = dt;
I am getting full data that is there in table. But I want only column names to be displayed one by one. Can any one help me out??
You can use ExecuteReader(CommandBehavior.SchemaOnly)):
DataTable schema = null;
using (var con = new SqlConnection(connection))
{
using (var schemaCommand = new SqlCommand("SELECT * FROM Add_Information", con))
{
con.Open();
using (var reader = schemaCommand.ExecuteReader(CommandBehavior.SchemaOnly))
{
schema = reader.GetSchemaTable();
}
}
}
datagridFieldCreation.DataSource = schema;
SchemaOnly:
The query returns column information only. When using SchemaOnly, the
.NET Framework Data Provider for SQL Server precedes the statement
being executed with SET FMTONLY ON.
The column name is in the first column of every row.
foreach (DataRow col in schema.Rows)
{
Console.WriteLine("ColumnName={0}", col.Field<String>("ColumnName"));
}
Adpated from: Using GetSchemaTable() to retrieve only column names
You can use:
SELECT * FROM YOURTABLENAME WHERE 0=1
Yes for sure, it is simple query which has a conditional statement which is always returning false, so each time you execute the query no rows will be extracted and only columns you will get so you can easily put up these columns in you DataGridView.
I'm looking at the example here:
http://msdn.microsoft.com/en-US/library/y06xa2h1(v=vs.80).aspx
string s = "primaryKeyValue";
DataRow foundRow = dataSet1.Tables["AnyTable"].Rows.Find(s);
if (foundRow != null)
{
MessageBox.Show(foundRow[1].ToString());
}
else
{
MessageBox.Show("A row with the primary key of " + s + " could not be found");
}
They don't specify where does dataSet1 come from and does this represent some database?
I'm trying to use this example in my code to find unique rows but I can't seem to implement this syntax. I'm only using connection string to open connection to SQL and I use SqlDataAdapter to perform functions...
EDIT:
SqlConnection myConnection = new SqlConnection("Data Source=server; Initial Catalog=Dashboard; Integrated Security=SSPI; Persist Security Info=false; Trusted_Connection=Yes");
SqlDataAdapter da = new SqlDataAdapter();
try
{
//Opens the connection to the specified database
myConnection.Open();
//Specifies where the Table in the database where the data will be entered and the columns used
da.InsertCommand = new SqlCommand("INSERT INTO DashboardLibAnswer(Id,Date,Time,Question,Details,Answer,Notes,EnteredBy,WhereReceived,QuestionType,AnswerMethod,TransactionDuration)"
+ "VALUES(#Id,#Date,#Time,#Question,#Details,#Answer,#Notes,#EnteredBy,#WhereReceived,#QuestionType,#AnswerMethod,#TransactionDuration)", myConnection);
//Specifies the columns and their variable type where the data will be entered
//Special note: Conversion from String > DateTime will cause exceptions that will only import some part of data and not everything
da.InsertCommand.Parameters.Add("#Id", SqlDbType.NVarChar);
da.InsertCommand.Parameters.Add("#Date", SqlDbType.Text);
da.InsertCommand.Parameters.Add("#Time", SqlDbType.Text);
da.InsertCommand.Parameters.Add("#Question", SqlDbType.Text);
da.InsertCommand.Parameters.Add("#Details", SqlDbType.Text);
da.InsertCommand.Parameters.Add("#Answer", SqlDbType.Text);
da.InsertCommand.Parameters.Add("#Notes", SqlDbType.Text);
da.InsertCommand.Parameters.Add("#EnteredBy", SqlDbType.NVarChar);
da.InsertCommand.Parameters.Add("#WhereReceived", SqlDbType.NVarChar);
da.InsertCommand.Parameters.Add("#QuestionType", SqlDbType.NVarChar);
da.InsertCommand.Parameters.Add("#AnswerMethod", SqlDbType.NVarChar);
da.InsertCommand.Parameters.Add("#TransactionDuration", SqlDbType.NVarChar);
//Using the global variable counter this loop will go through each valid entry and insert it into the specifed database/table
for (int i = 0; i < counter; i++)
{
//Iterates through the collection array starting at first index and going through until the end
//and inserting each element into our SQL Table
DataSet dashboardDS = new DataSet();
da.Fill(dashboardDS, "DashboardLibAnswer");
DataTable dt = dashboardDS.Tables["DashboardLibAnswer"];
foreach (DataColumn col in dt.Columns)
{
if (col.Unique)
{
da.InsertCommand.Parameters["#Id"].Value = collection.getIdItems(i);
da.InsertCommand.Parameters["#Date"].Value = collection.getDateItems(i);
da.InsertCommand.Parameters["#Time"].Value = collection.getTimeItems(i);
da.InsertCommand.Parameters["#Question"].Value = collection.getQuestionItems(i);
da.InsertCommand.Parameters["#Details"].Value = collection.getDetailsItems(i);
da.InsertCommand.Parameters["#Answer"].Value = collection.getAnswerItems(i);
da.InsertCommand.Parameters["#Notes"].Value = collection.getNotesItems(i);
da.InsertCommand.Parameters["#EnteredBy"].Value = collection.getEnteredByItems(i);
da.InsertCommand.Parameters["#WhereReceived"].Value = collection.getWhereItems(i);
da.InsertCommand.Parameters["#QuestionType"].Value = collection.getQuestionTypeItems(i);
da.InsertCommand.Parameters["#AnswerMethod"].Value = collection.getAnswerMethodItems(i);
da.InsertCommand.Parameters["#TransactionDuration"].Value = collection.getTransactionItems(i);
da.InsertCommand.ExecuteNonQuery();
}
}
//Updates the progress bar using the i in addition to 1
_worker.ReportProgress(i + 1);
} // end for
//Once the importing is done it will show the appropriate message
MessageBox.Show("Finished Importing");
} // end try
catch (Exception exceptionError)
{
//To show exceptions thrown just uncomment bellow line
//rtbOutput.AppendText(exceptionError.ToString);
} // end catch
//Closes the SQL connection after importing is done
myConnection.Close();
}
if you populate a dataset from your data adapter, you'll be able to follow the same logic -
http://msdn.microsoft.com/en-us/library/bh8kx08z(v=vs.71).aspx
It might be worth showing what you actually have to get more specific help
EDIT
I think I'm understanding what you want - if you fill your datatable from the already populated table, just check the item doesn't already exist before adding it - i.e.
if (dt.Rows.Find(collection.getIdItems(i)) == null)
{
// add your new row
}
(just to be sure I knocked together a quick test - hopefully this helps):
// MyContacts db has a table Person with primary key (ID) - 3 rows - IDs 4,5,6
SqlConnection myConnection = new SqlConnection("Data Source=.; Initial Catalog=MyContacts; Integrated Security=SSPI; Persist Security Info=false; Trusted_Connection=Yes");
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = new SqlCommand("select * from Person", myConnection);
myConnection.Open();
DataSet dashboardDS = new DataSet();
da.Fill(dashboardDS, "Person");
dashboardDS.Tables[0].PrimaryKey = new[] { dashboardDS.Tables[0].Columns["ID"]};
List<int> ids = new List<int> {4, 6, 7};
foreach (var id in ids)
{
if (dashboardDS.Tables[0].Rows.Find(id) == null)
{
Console.WriteLine("id not in database {0}", id); //i.e. 7
}
}
You will first need to open a connection to your database. This is an excellent source for connection strings: The Connection String Reference.
Then you will need to fill the dataset with data from some table. Since we are only interested in the schema information we are only selecting one row (SELECT TOP 1 ...).
Then we can go through the columns and check their Unique property (Boolean):
string connString =
"server=(local)\\SQLEXPRESS;database=MyDatabase;Integrated Security=SSPI";
string sql = #"SELECT TOP 1 * FROM AnyTable";
using (SqlConnection conn = new SqlConnection(connString)) {
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(sql, conn);
using (DataSet ds = new DataSet()) {
da.Fill(ds, "AnyTable");
DataTable dt = ds.Tables["AnyTable"];
foreach (DataColumn col in dt.Columns) {
if (col.Unique) {
Console.WriteLine("Column {0} is unique.", col.ColumnName);
}
}
}
}
UPDATE #1
Sorry, I missunderstood your question. The above example returns unique columns, not unique rows. You can get unique (distinct) rows by using the DISTINCT keyword in SQL:
SELECT DISTINCT field1, field2, field3 FROM AnyTable
You can then fill the data table the same way as above.
Usually the word "unique" is used for unique constraints and unique indexes in database jargon. The term "distinct" is used for rows which are different.
UPDATE #2
Your updated question seems to suggest that you don't want find unique rows, but that you want to insert unique rows (which is the exact opposite).
Usually you would select distinct items from a collection like this. However it is difficult to answer your question accurately, since we don't know the type of your collection.
foreach (var item in collection.Distinct()) {
}
UPDATE #3
The easiest way to insert distinct values in the SQL Server table is to filter the rows at their origin, when reading them from the CSV-File; even before splitting them.
string[] lines = File.ReadAllLines(#"C:\Data\MyData.csv");
string[][] splittedLines = lines
.Distinct()
.Select(s => s.Split(','))
.ToArray();
Now you have distinct (unique) splitted lines that you can insert into the SQL Server table.
i want to extract my table names and save it into variables this is my cod that return 3 answer:student, teacher and score. how can i change it to save these tree table name to 3 variable. thank you.
try
{
SqlDataReader myreader = null;
SqlCommand mycommand = new SqlCommand("select * FROM information_schema.tables WHERE table_type = 'BASE TABLE'", myconnect);
myreader = mycommand.ExecuteReader();
while (myreader.Read())
{
Console.WriteLine(myreader[2].ToString());
}
}
A simple builtin way is using Connection.GetSchema:
using (var con = new System.Data.SqlClient.SqlConnection(conStr))
{
con.Open();
DataTable schemaTable = con.GetSchema("Tables");
IList<string> allTableNames = schemaTable.AsEnumerable()
.Where(r => r.Field<string>("TABLE_TYPE") == "BASE TABLE")
.Select(r => r.Field<string>("TABLE_NAME"))
.ToList();
}
Now you have a List<string> with all table names which you can access via indexer or in a loop or create a comma separated list with string.Join:
string tNames = string.Join(",", allTableNames);
Console.Write("all tables in the given database: " + tNames);
You can use this :
string tableName ="" ; // Variable to stroe the table names
string connectionString = ""; //Your connectionstring
// get records from the table
string commandString =""; //Your query
// create the data set command object
// and the DataSet
SqlDataAdapter DataAdapter =new SqlDataAdapter(commandString, connectionString);
DataSet DataSet = new DataSet( );
// fill the DataSet object
DataAdapter.Fill(DataSet, "Customers");
// Get the one table from the DataSet
DataTable dataTable = DataSet.Tables[0];
// for each row in the table, display the info
foreach (DataRow dataRow in dataTable.Rows)
{
tableName = dataRow[0].tostring();
//...
}
if you want to save the result for future user or a different session then you can use any of the following to methods
first one
use the "insert" query to save the result one by one in the a different table that you would create specially for saving the data
you can put the insert command/statement directly into the for loop
second method
use the xml to store the value very simple and memory friendly
I Have modified #Doctor code to use ArrayList to store number of table name in single variables.
ArrayList alTableName = new ArrayList(); // Variable to stroe the table names
string connectionString = ""; //Your connectionstring
// get records from the table
string commandString =""; //Your query
// create the data set command object
// and the DataSet
SqlDataAdapter DataAdapter =new SqlDataAdapter(commandString, connectionString);
DataSet DataSet = new DataSet( );
// fill the DataSet object
DataAdapter.Fill(DataSet, "Customers");
// Get the one table from the DataSet
DataTable dataTable = DataSet.Tables[0];
// for each row in the table, display the info
foreach (DataRow dataRow in dataTable.Rows)
{
alTableName.Add(dataRow[0].tostring());
//...
}
I currently have a DataGridView which displays all the item. I would like to sum all the prices in the price column and then reflect the total in a label, 'TotalValueLabel'. What's wrong with my statement?
string query = "SELECT SUM (Price) FROM Bill";
OleDbDataAdapter dAdapter = new OleDbDataAdapter(query, DBconn);
DataTable source = new DataTable();
dAdapter.Fill(source);
TotalValueLabel.Text = source.ToString();
Your source is a DataTable so "source.ToString()" will not give you your result,
Try "source.Rows[0][0].ToString();".
DataTable object contains a list of DataRow objects which hold values for each row of your query result.
In your case however you might not need this. If you are looking for a single value you should use IDbCommand and call ExecuteScalar(). This will return the first value of the first row of your results.
Also try calling Dispose() on objects that implement IDisposable (like dbadapter, command, connection).
string query = "SELECT SUM (Price) FROM Bill";
using (System.Data.IDbCommand command = new System.Data.OleDb.OleDbCommand(query, DBconn))
{
object result = command.ExecuteScalar();
TotalValueLabel.Text = Convert.ToString(result);
}
DataTable is overkill for single value retrieval, besides your not even accessing the value correctly, better way is to use execute scalar:
var query = "SELECT SUM (Price) FROM Bill";
using (var cmd = new OleDbCommand(query, DBcon))
{
TotalValueLabel.Text = cmd.ExecuteScalar().ToString();
}