Query returns results 5 times - c#

I have a weird problem. My query in C#/ASP.NET returns results 5 times. I tried brakepoint-ing but I can't find the error. I have 2 related tables. One table loads on PAGE_LOAD and when the user click on a cell, it shows the content from another table related to that cell. It's very simple.
//PAGE LOAD
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
OleDbConnection myConnection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + dbpath + "/secure_user/data/data.mdb");
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT Project,Manager,Customer,Deadline FROM projects WHERE Username='" + uname + "'", myConnection);
DataTable table = new DataTable();
adapter.Fill(table);
adapter.Dispose();
GridView1.DataSource = table;
GridView1.DataBind();
}
}
It loads projects table to the GridView. Now when I click a certain project, it displays more information about that project:
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
GridViewRow row = GridView1.SelectedRow;
Label1.Text = row.Cells[1].Text;
OleDbConnection myConnection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + dbpath + "/secure_user/data/data.mdb");
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT tasks.Task,tasks.Priority,tasks.Done,taska.Hours FROM projects,tasks WHERE tasks.Username='" + uname + "' AND tasks.Project='" + Label1.Text + "'", myConnection);
DataTable table = new DataTable();
adapter.Fill(table);
adapter.Dispose();
GridView2.DataSource = table;
GridView2.DataBind();
GridView2.Visible = true;
}
It displays with no error, but it does 5 times no matter what project I select from GridView1, it always displays GridView2 (second table) content 5 times in a row. What could be the problem?

Looks like you have something wrong in your query. Try using INNER JOIN instead of ,.
Instead of this:
SELECT tasks.Task, tasks.Priority, tasks.Done, tasks.Hours
FROM projects, tasks
WHERE tasks.Username='" + uname + "' AND tasks.Project='" + Label1.Text + "'
Try this:
SELECT tasks.Task, tasks.Priority, tasks.Done, tasks.Hours
FROM projects INNER JOIN tasks ON projects.ID = tasks.ProjectID --> may not be correct depends on your table structure
WHERE tasks.Username='" + uname + "' AND tasks.Project='" + Label1.Text + "'
Another thing: building a SQL query like that is prone to SQL Injection attack.

You are doing cross join between the projects table and the tasks table, so you are joining every project with each task for the project that you selected. As you have five projects you get each task five times.
Use a join to specify the relation between the projects table and the tasks table:
OleDbDataAdapter adapter = new OleDbDataAdapter(
"SELECT tasks.Task,tasks.Priority,tasks.Done,taska.Hours "+
"FROM projects "+
"INNER JOIN tasks ON tasks.Project = projects.Project "+
"WHERE projects.Username='" + uname + "' AND projects.Project='" + Label1.Text + "'", myConnection);
Note:
Notice that I used the Username field in the projects table rather than the tasks table. Either you have redundancy in the tables, or the fields mean different things. If some other user can add tasks to your project you would need a condition for the tasks.Username field also if you only want to see the tasks that you added yourself.

Could be that this query is returning multiple records; can you list primary keys in the used tables

In your second query you have a join, of sorts. You never return anything in the SELECT from the projects table, but it is referenced in the query. I'm guessing that you have 5 projects.
Also, you are injecting data into the query. This is bad as it becomes very easy for an attacker to mount a SQL Injection attack against your code and database, especially as you are using data directly from controls. You should consider using at least parameterised queries.

You try adding to your query DISTINCT clause. Because if it is not presented, your query did a cartesian product.
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT DISTINCT tasks.Task,tasks.Priority,tasks.Done,taska.Hours FROM projects,tasks WHERE tasks.Username='" + uname + "' AND tasks.Project='" + Label1.Text + "'", myConnection);

Related

Search bar in C# to search for data where string is equal to value C#

I've written a program which includes a datagridview and search bar. The user is required to log in to the software before use and will be shown data related to their unique ID which is stored as a string within the program and the user can only see their own records in the datagridview and nobody else. My search bar works fine functionally but when you delete the text in the datagridview it refreshes and shows all the data in my table rather than just the logged in users data.
This is my code.
SqlDataAdapter sda = new SqlDataAdapter("Select * from Leads where Full_Name like'" + textBox2.Text + "%' or Company like'" + textBox2.Text + "%' where Owner='" + User_ID + "'", con);
DataSet ds = new DataSet();
sda.Fill(ds, "Leads");
dataGridView4.DataSource = ds.Tables[0];
As others have mentioned, it appears that you have a problem with your SQL statement having two where clauses.
Reformmatted:
SqlDataAdapter sda = new SqlDataAdapter($"Select * from Leads where (Full_Name like '{textBox2.Text}%' or Company like '{textBox2.Text}%') and Owner = '{User_ID}'", con);
The and before Owner could be whatever operator you need depending on your use case.
I also changed the text to use $string interpolation which can look a bit cleaner and easier to read.

change sql query using selected text in combobox

I'm writing a program using MySQL and WinForm. In my program there's an option to select a VAT Number from a combobox that is retrieve from a table in database. After selecting a VAT Number user have to enter 2 different values into 2 different textbox. After entering those values, the sql query will execute. And show the result in another textbox.
Application form
My sql queries are working fine.
using(MySqlConnection con = new MySqlConnection(cs))
{
con.Open();
//string command;
string command = #"SELECT * FROM `db_liq_blnd_calc_sys`.`tbl_vat_12_spirit_sa` WHERE DIP = '" + txt_Calc_BULK_DIP.Text + "' AND SLIDE = '" + txt_Calc_BULK_SLIDE.Text + "'";
MySqlDataAdapter da = new MySqlDataAdapter(command, con);
DataTable dtable = new DataTable();
DataSet ds = new DataSet();
da.Fill(ds);
DataRow[] returnrow = ds.Tables[0].Select("DIP = '" + txt_Calc_BULK_DIP.Text + "' AND SLIDE = '" + txt_Calc_BULK_SLIDE.Text + "'");
int result = returnrow.Length;
DataRow dr = returnrow[0];
txt_Calc_BULK_BULK.Text = (dr["BULK"].ToString());
con.Close();
}
What I wanna do is, there are 15 table in my database that has same table structure but different data in it. I want to change the sql query that execute by selecting different VAT Number from the combobox.
Since all tables have the same structure, I recommend making one big table for them all and add a VAT Number column to it. Then, to set the values in your combobox, select distinct VAT Numbers from this table. Finally, add the a VAT Number condition to your query.
On a side note, use "Parameterized Query" instead of concatenating values to your query, this would help against SQL Injection Attacks.

Using an MS Access Lookup field in C#

I am building an extension to an existing Access database and an accompanying front end programmed in C#. The original Access database was not designed very well and certainly not designed with future expansion in mind. For simplicity's sake, lets say the legacy DB has 2 tables: tblEmployee [empId(AutoNumber), empName(Text)] and tblProjects [prjId(AutoNumber), prjName(Text), prjEmps(Number/Lookup)]. Both tables have an AutoNumber primary key. The Projects table has a multi-value lookup field that allows users to assign multiple employees to a project. When I query the tblProjects table in Access SELECT prjId, prjName, prjEmps FROM tblProject;, the prjEmps field lists all the employees' names separated by commas. However, the problem is when I use the same query in C#, the prjEmps returns a string version of a number that is not the empId of the employee(s). I am not sure if it makes a difference, but I am using the System.Data.OleDb and System.Data namespaces in C#. Here is the gist my C# code:
string connStr = #"Provider = Microsoft.ACE.OLEDB.12.0; " +
#"Data Source=" + dbFilePath;
string query = "SELECT prjId, prjName, prjEmps FROM tblProject;";
OleDbConnection dbConn = new OleDbConnection(connStr);
OleDbCommand Cmd = new OleDbCommand(query, dbConn);
OleDbDataAdapter adp = new OleDbDataAdapter(query, dbConn);
DataTable dt = new DataTable();
adp.Fill(dt);
dbConn.Close();
foreach (DataRow row in dt.Rows)
{
int prjId = row.Field<int>("prjId");
string prjName = row.Field<string>("prjName");
string prjEmps = row.Field<string>("prjEmps");
MessageBox.Show("Project ID: " + prjId.ToString() + "\n" +
"Project Name: " + prjName + "\n" +
"Employees: " + prjEmps);
}
I would be happy if I could just get the concatenated list of names, but I would prefer an array of integer keys or the like. Any ideas on how to fix this?
Use ODBC provider, OLEDB does not supports multi-value lookup field and you get garbage values if you use it to read multi-value lookup field , using ODBC you will get ";" separated values which can then be split into individual values or replace with ",".

Save changes in database using BindingSource

I retrieve data from database like this:
OleDbDataAdapter dataAdapter
= new OleDbDataAdapter("SELECT * "
+ " FROM myTab1, myTab2"
+ " WHERE myTab1.col1 = myTab2.col3"
, connection);//OleDbConnection connection = new OleDbConnection();
DataTable dataTable = new DataTable("myDataTable");
BindingSource bindingSource = new BindingSource();
bindingSource.DataSource = dataTable;
dataAdapter.Fill(dataTable);
Then I use bindingSource in order to access the data in my program, everything works perfect. But after all changes I've made in bindingSource, I need so save them into the database. How can I do this?
Well normally you'd call Update() on the DataAdapter:
dataAdapter.Update(dataTable);
But since your query "joins" two tables it may not be so easy. It may be possible if you turn your SELECT query into a proper join:
"SELECT * "
+ "FROM myTab1 "
+ "JOIN myTab2 ON myTab1.col1 = myTab2.col3"
Some other alternatives:
Write an UPDATE statement that will put the right values in the right tables and set your dataAdapter's UpdateStatement
Populate the dataset with separate tables (one per base table) and join in your app
More info from MSDN:
http://msdn.microsoft.com/en-us/library/xzb1zw3x(v=vs.80).aspx

How can I see the data of a SQL server database in c#, and where it's store?

I have a program written in c# visual studio 2008 with SQL server 2005 (.mdf) database.
Here is part of the code:
...
SqlCommandBuilder cb;
cb = new SqlCommandBuilder(dataAdapter);
String[] dataList =new String [8];
...
DataTable resultTable = new DataTable();
FillDataList(data);
dataAdapter = new SqlDataAdapter("insert into ProcessData values('" + dataList[0] + "','" + dataList[1] + "','" + dataList[2] + "','" + dataList[3] + "','" + dataList[4] + "','" + dataList[5] + "','" + dataList[6] + "','" + dataList[7]+"')", con);
dataAdapter.Fill(resultTable);
...
My questions are:
1) Where is the data I added in those lines stored?
2) Why is it that when I Right-Click with the mouse in the Server Explorer->Data Connections->Tables->ProcessData (my table's name)->"show Table Data", I don't see the data but just NULL in the columns, and how can i see the data there?
3) Why when I present this data in a DataGridView sometimes it shows the data and sometimes it doesn't?
Many Thanks!
Without seeing more info on the datalist object and its construction, it's impossible to say. However, you're using the Fill and SQLDataAdapter incorrectly. The FILL relies on the SQLDataAdapter having a SelectCommand property set, which is what your code is bunging the INSERT statement into (that's what the SQLDataAdapter's constructor does). So...your Fill returns nothing as there's no SELECT where there should be.
Your INSERT should be part of the dataadapter's InsertCommand, and you'll need to write a separate SELECT statement to get anything into your resultTable.
I think you need to read some basic documentation on ADO.NET before you write any more code. You're passing an INSERT statement to the SqlDataAdapter constructor, which takes a SELECT statement. You're using the Fill method of SqlDataAdapter where you should be using the Update method. You're building a SQL string with hard-coded values in it where you should be using SqlParameters with references to the DataTable Columns. And is the fact that your DataTable is called "data" but that SQL string is using indexed properties from "dataList" just a typo? Because if it is, DataTable doesn't have an indexed property.
Try doing it like this (you need to fill in the correct connection string though):
// Get the db connection
SqlConnection dbCon = new SqlConnection("connection string");
// Select the data from the database table into a DataSet (even if it's empty)
DataSet myData = new DataSet();
SqlDataAdapter dbAdapter = new SqlDataAdapter("select * from ProcessData", dbCon);
dbAdapter.Fill(myData);
myData.Tables[0].TableName = "ProcessData"; // Keeps the table name consistent for the DataMember property
// Use the command builder to add insert, delete, update commands to your adapter
// You must have a primary key on the table for these to work, though
SqlCommandBuilder dbComBuilder = new SqlCommandBuilder(dbAdapter);
dbAdapter.InsertCommand = dbComBuilder.GetInsertCommand();
dbAdapter.DeleteCommand = dbComBuilder.GetDeleteCommand();
dbAdapter.UpdateCommand = dbComBuilder.GetUpdateCommand();
// Bind the data set to the GridView for viewing / editing
yourGridControl.AutoGenerateColumns = true; // Optional, if you haven't manually added the columns
yourGridControl.DataSource = myData;
yourGridControl.DataMember = "ProcessData";
// Use the db adapter to update the database (by calling those commands) with
// changes made to the DataSet through the grid. This would go in a different
// form event, like a Save Button click.
dbAdapter.Update();
If you don't have a primary key in the ProcessData table, you can directly insert values using this command:
// Insert the data directly with a command
SqlCommand dbInsCommand = new SqlCommand("insert into ProcessData values (" + val1 + "," + val2 + ")", dbCon);
dbInsCommand.ExecuteNonQuery();

Categories

Resources