I have a database with two tables. Both of these tables are related and have the same key field. For example, both of them have rows of data corresponding to ISBN = 12345, but the two tables have differing data about that ISBN.
So, I'm trying to figure out how to display data from both tables into one dataGridView. I have tried some SQL commands I found online, but it looks like commands in C# might differ from normal SQL queries.
Suppose table1 has these fields: ISBN, color, size and table2 has the fields ISBN, weight.
I need a way to display ISBN, color, size, weight in my datagrid view. I think I will have to somehow do this with an adapter. I am able to connect and do queries on the tables individually, and show that data in my datagridview, but I can't figure out how to mix data from two separate tables.
If you have a good resource I can read about this I'd love to have it, my google-fu is failing me.
Here's an example of something I can do now with my database:
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'database1DataSet.Book' table. You can move, or remove it, as needed.
this.bookTableAdapter.Fill(this.database1DataSet.Book);
string connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + #"C:\Users\Geoff\Documents\cs 351\Database1.accdb" + ";Persist Security Info=False;";
OleDbConnection conn = new OleDbConnection(connectionString);
string query = "select * from Book where ISBN = 12345";
OleDbCommand com = conn.CreateCommand();
com.CommandText = query;
OleDbDataAdapter adapter = new OleDbDataAdapter(com);
DataSet data = new DataSet();
conn.Open();
adapter.Fill(data);
conn.Close();
dataGridView1.DataSource = data.Tables[0];
}
So, essentially, I'd like to do what I've done above, but I want to include the data from a different table too. The other table also has a key field ISBN, and it contains values of ISBN that match the first table.
Look into the use of JOIN to return the results from two tables JOINed together ON some common value
See Also
Wikpedia: Join
(SQL)
W3Schools: SQL
Joins
SQL-tutorial.net: SQL
Join
SO: SQL JOIN ON vs WHERE
Coding Horror: visual explanation of SQL JOINs
There's nothing limiting this to C# or OLEDB -- it's basic SQL.
For the specifics of what you're asking a query might look like the following:
SELECT T1.ISBN, T1.color, T1.size, T2.weight
FROM table1 T1
INNER JOIN table2 T2
ON T1.ISBN = T2.ISBN
WHERE ISBN = '12345';
(There's no need to alias table1 as T1 -- I just did that as an example; in more complicated queries with longer table names, you might not want to repeat the table name all the time)
since ISBN occurs in both tables, it must be explicitly qualified in your field-selections; either T1 or T2 can be used, as they are identical
since color, size and weight each occur in only one table, they do NOT need to be qualified -- but it doesn't hurt.
var query = "SELECT t1.isbn, t1.color, t1.size, t2.weight FROM table1 t1 JOIN table2 t2 ON t2.isbn = t1.isbn";
var connection = new System.Data.SqlClient.SqlConnection("your SQL connection string here");
var dataAdapter = new System.Data.SqlClient.SqlDataAdapter(query, connection);
var dataSet = new System.Data.DataSet();
dataAdapter.Fill(dataSet);
yourGridView.DataSource = dataSet;
yourGridView.DataBind();
This is one of many solutions. I think the code might be faster if you create an in-memory DataTable and use an SqlDataReader, but the sample above is simpler.
When working with MSSQL databases, you normally use the System.Data.SqlClient classes. If you - for whatever reason - use OleDb, pick the corresponding objects from the System.Data.OleDb namespace.
You can query records from both tables using UNION ALL
SELECT 'In table 1', book_author, book_title, book_isbn
FROM books
WHERE book_isbn = '67890'
UNION ALL
SELECT 'In table 2', othertable_author, othertable_title, othertable_isbn
FROM othertable
WHERE othertable_isbn = '67890'
of course you'll need to manually fill the '67890' in both places using whatever method is more convenient in your situation.
Related
I have a SQLite database contains several tables which some of them (not all) have a specific column called 'attachment'. I wonder if there is a query that get values of the 'attachment' column from all the tables which have this column. I can get all tables' name from the database, and then, query all tables individually. But I think there must be a single query to do this.
You can use SQLite code to get the sql SELECT statement as a string and execute it to get all the values of the column attachment in all tables of the database:
SELECT GROUP_CONCAT('SELECT ' || pti.name || ' FROM ' || sm.name, ' UNION ALL ') sql
FROM sqlite_master sm CROSS JOIN pragma_table_info(sm.name) pti
WHERE sm.type = 'table' AND pti.name = 'attachment';
The above query returns a resultset with only 1 row and 1 column aliased as sql with a value of a string like this:
SELECT attachment FROM table1
UNION ALL
SELECT attachment FROM table2
UNION ALL
SELECT attachment FROM table4
You can change UNION ALL to UNION inside the function GROUP_CONCAT(), depending on your requirement.
See a simplified demo.
You can get the values of every attachment field in every table that has this field defined using the GetSchema method on the connection to find all the relevant tables then you can use the sql stament UNION to extract in a single command all the attachments values.
This should be the code using only standard ADO.NET commands and methods:
using(SQLiteConnection cnn = new SQLiteConnection(#"Data Source=E:\\temp\\mydb.db;Version=3"))
{
cnn.Open();
// We want all columns with the name as "attachment"
DataTable dt = cnn.GetSchema("COLUMNS", new string[] {null, null, null, "attachment"});
// Now we prepare the single commands that extract the attachments value
// from every row returned by the previous query.
// The TABLE_NAME field contains the name of the relevant table
var s = dt.AsEnumerable().Select(x => $"SELECT attachment FROM [{x.Field<string>("TABLE_NAME")}]");
// We join together the single commands separating them with the UNION statement
string command = string.Join(" UNION ", s);
// Finally we can construct and execute a command loading a datatable
// with all the attachements values from every table.
SQLiteCommand cmd = new SQLiteCommand(command, cnn);
dt = new DataTable();
dt.Load(cmd.ExecuteReader());
// Here you can work on the single field in the _dt_ table
....
}
Note, UNION will extract a distinct value for each attachment. This means that if you have two attachments with the same name, it will be listed only one time. If you want to keep everything then change UNION to UNION ALL (with spaces before and after the statement)
I have two Sql Server databases d1 and d2 which are in the same physical server. d1 has a table address, d2 has a table telephone. I want to join them in a C# project, I googled and tried many ways, but all failed. If anybody can provide a simple but "COMPLETE and RUNNABLE" C# example project, that would be greatly appreciated.
[d1].[dbo].[address]:
id name address
1 Adam add1
2 Bob add2
3 Pete add3
4 Hans add4
[d2].[dbo].[telephone]:
id addr_id phoneNumber
1 2 632532
2 1 233257
3 4 343439
4 3 798111
addr_id is a foreign key with the reference to id of table address in database d1.
ConnectionString_d1 = "Data Source=ServerName;" + "Initial Catalog=d1;" + "User id=ui;" + "Password=pd;";
ConnectionString_d2 = "Data Source=ServerName;" + "Initial Catalog=d2;" + "User id=ui;" + "Password=pd;";
Certainly, you need change the two connection strings according to your own databases for the test.
SELECT t1.name, t1.address, t2.phoneNumber
FROM [d1].[dbo].[address] t1
INNER JOIN [d2].[dbo].[address] t2
ON t1.id = t2.addr_id;
Please don't just tell me the T-Sql statement mentioned above that only works in MSSQL Management Studio, doesn't work in a C# project. I need the simple but the COMPLETE Implementation of a C# console application that can be built and run, thanks in advance!
SQL Server can join separate tables from different databases fairly easily. If your query requirements become more complex, then you just alter the query to return the data you're needing (i.e 5 tables from 3 databases). The SQL you provided works just fine for returning data from multiple tables from different databases:
SELECT t1.name, t1.address, t2.phoneNumber
FROM [d1].[dbo].[address] t1
INNER JOIN [d2].[dbo].[address] t2
ON t1.id = t2.addr_id;
If you are wanting to filter down the results more, then you should add a WHERE clause as well.
You can create this to a Stored Procedure like so:
--To be ran on your SQL Server and not from C# program
USE [d1]
GO
CREATE PROCEDURE [d1].[dbo].[MyProcedureName]
--add parameters if needed
AS
BEGIN
SET NOCOUNT ON
SELECT t1.name,
t1.address,
t2.phoneNumber
FROM [d1].[dbo].[address] t1
INNER JOIN [d2].[dbo].[address] t2 ON t1.id = t2.addr_id;
END
With the Stored Procedure created, you can then use C# to call it, and return the result.
Here is a C# method I have that I only use to call a stored procedure and return it as a DataTable:
//using System.Data.SqlClient;
public DataTable SqlToDT (string connectionString, string procName)
{
//receives connection string and stored procedure name
//then returns the populated data table
DataTable table = new DataTable();
using (var connection = new SqlConnection(connectionString))
using (var cmd = new SqlCommand(procName, connection))
using (var adapter = new SqlDataAdapter(cmd))
{
cmd.CommandType = CommandType.StoredProcedure;
da.Fill(table);
} //the using statements will dispose the connection safely for you
return table;
}
You can use this method like so:
//using System.Data;
//Got rid of the needless string concatenation
string connectionStringd1 = "Data Source=ServerName;Initial Catalog=d1;User id=ui;Password=pd;";
string procName = "MyProcedureName";
DataTable myTable = new DataTable();
myTable = SqlToDT(connectionStringd1, procName);
//continue on from here
I dont know how to do this query in c#.
There are two databases and each one has a table required for this query. I need to take the data from one database table and update the other database table with the corresponding payrollID.
I have two tables in seperate databases, Employee which is in techData database and strStaff in QLS database. In the employee table I have StaffID but need to pull the PayrollID from strStaff.
Insert payrollID into Employee where staffID from strStaff = staffID from Employee
However I need to get the staffID and PayrollID from strStaff before I can do the insert query.
This is what I have got so far but it wont work.
cn.ConnectionString = ConfigurationManager.ConnectionStrings["PayrollPlusConnectionString"].ConnectionString;
cmd.Connection = cn;
cmd.CommandText = "Select StaffId, PayrollID From [strStaff] Where (StaffID = #StaffID)";
cmd.Parameters.AddWithValue("#StaffID", staffID);
//Open the connection to the database
cn.Open();
// Execute the sql.
dr = cmd.ExecuteReader();
// Read all of the rows generated by the command (in this case only one row).
For each (dr.Read()) {
cmd.CommandText = "Insert into Employee, where StaffID = #StaffID";
}
// Close your connection to the DB.
dr.Close();
cn.Close();
Assuminig, you want to add data to existing table, you have to use UPDATE + SELECT statement (as i mentioned in a comment to the question). It might look like:
UPDATE emp SET payrollID = sta.peyrollID
FROM Emplyoee AS emp INNER JOIN strStaff AS sta ON emp.staffID = sta.staffID
I have added some clarity to your question: the essential part is that you want to create a C# procedure to accomplish your task (not using SQL Server Management Studio, SSIS, bulk insert, etc). Pertinent to this, there will be 2 different connection objects, and 2 different SQL statements to execute on those connections.
The first task would be retrieving data from the first DB (for certainty let's call it source DB/Table) using SELECT SQL statement, and storing it in some temporary data structure, either per row (as in your code), or the entire table using .NET DataTable object, which will give substantial performance boost. For this purpose, you should use the first connection object to source DB/Table (btw, you can close that connection as soon as you get the data).
The second task would be inserting the data into second DB (target DB/Table), though from your business logic it's a bit unclear how to handle possible data conflicts if records with identical ID already exist in the target DB/Table (some clarity needed). To complete this operation you should use the second connection object and second SQL query.
The sample code snippet to perform the first task, which allows retrieving entire data into .NET/C# DataTable object in a single pass is shown below:
private static DataTable SqlReadDB(string ConnString, string SQL)
{
DataTable _dt;
try
{
using (SqlConnection _connSql = new SqlConnection(ConnString))
{
using (SqlCommand _commandl = new SqlCommand(SQL, _connSql))
{
_commandSql.CommandType = CommandType.Text;
_connSql.Open();
using (SqlCeDataReader _dataReaderSql = _commandSql.ExecuteReader(CommandBehavior.CloseConnection))
{
_dt = new DataTable();
_dt.Load(_dataReaderSqlCe);
_dataReaderSql.Close();
}
}
_connSqlCe.Close();
return _dt;
}
}
catch { return null; }
}
The second part (adding data to target DB/Table) you should code based on the clarified business logic (i.e. data conflicts resolution: do you want to update existing record or skip, etc). Just iterate through the data rows in DataTable object and perform either INSERT or UPDATE SQL operations.
Hope this may help. Kind regards,
In my database i have three tables. One For employs where i keep their names, ids, salary... In the second one named Project i keep id, location, name. in the third one named WorksOn i keep the id from employs and the id from project. In my Asp .Net web site in gridview i need to display the employee's name and the name of the project that he is working.
string connect =
WebConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString;
SqlConnection con = new SqlConnection(connect);
try
{
con.Open();
}
catch (Exception err)
{
string error = err.Message;
con.Close();
}
SqlCommand command = new SqlCommand();
command.Connection = con;
SqlDataReader reader;
command.CommandText = "SELECT * FROM WorksON ";
reader= command.ExecuteReader();
In data source in gridview if i choose to display the values from WorksOn table it shows the id from employs and the id from project but what i need is to show the names on the employs and project.
I know that i need to do something with dataset but i don't know who.
Your SQL command must JOIN the related tables. Something like:
SELECT * FROM WorksOn JOIN Employee on WorksOn.EmployeeId = Employee.Id
Note that you should not SELECT "*" (all columns). You should only SELECT those columns that are necessary to your data view for performance.
On your SQL command, you don't mention anything about Employs. You need to use a JOIN SQL command in order to get both the employee name and the company name.
And instead of using "SELECT * FROM...", consider using the columns name instead, because you're not trying to get all the columns display. And it will help us understand the name of the columns to further help you.
Use a JOIN query like this:
SELECT project.projectName, employee.Name
FROM (worksOn
INNER JOIN employee
ON (worksOn.employeeId = employee.employeeId))
INNER JOIN project
ON (project.projectId = employee.employeeId)
AND (worksOn.projectId = project.projectId)
i would like to know what is the standard/best way of doing the following:
i have a form web app in asp.net and using C#
the user will enter data into the form and click INSERT and it will insert data into 4 different tables.
the fields are:
primarykey, animal, street, country
the form allows for multiple animals, multiple streets and multiple countries per primarykey. so when i have data like this:
[1],[rhino,cat,dog],[luigi st, paul st], [russia,israel]
i need it inserted into tables like this:
table1:
1,rhino
1,cat
1,dog
table2:
1,luigi st
1, paul st
table3:
1,russia
1,israel
questions
I'm at a total loss on how to do this. if i just had one table and one set of data per primary key i would just use the InsertQuery and do it this way, but since it is multiple tables i don't know how to do this??
what control(s) should i use in order to allow user to input multiple values? currently i am just using textboxes and thinking of separating the entries by semi colons, but that's probably not the right way.
I wanted to recommend that you take advantage of the new multirow insert statement in SQL 2008 so that you can just pass a sql statement like this:
INSERT INTO table1(id,animal_name) values (1,cat),(1,dog),(1,horse)...
To your SqlCommand but I don't know how to build a statement like that w/o risking being victim of a SQL Injection Attack.
Another alternative is to define data table types in your sql database:
And then construct a DataTable in C# that matches your datatable type definition:
DataTable t = new DataTable();
t.Columns.Add("id");
t.Columns.Add("animal_name");
foreach(var element in your animals_list)
{
DaraRow r = t.NewRow();
r.ItemArray = new object[] { element.id, element.animal_name };
t.Rows.Add(r);
}
// Assumes connection is an open SqlConnection.
using (connection)
{
// Define the INSERT-SELECT statement.
string sqlInsert = "INSERT INTO dbo.table1 (id, animal_name) SELECT nc.id, nc.animal_name FROM #animals AS nc;"
// Configure the command and parameter.
SqlCommand insertCommand = new SqlCommand(sqlInsert, connection);
SqlParameter tvpParam = insertCommand.Parameters.AddWithValue("#animals", t);
tvpParam.SqlDbType = SqlDbType.Structured;
tvpParam.TypeName = "dbo.AnimalTable";
// Execute the command.
insertCommand.ExecuteNonQuery();
}
Read more here.
Or if you are familiar with Stored Procedures, same as previous suggestion but having the stored procedure receive the DataTable t as parameter.
If none of the above work for you, create a SqlTranscation from the Connection object and iterate through each row of each data set inserting the record in the appropriate table and finally commit the transaction. Example here.
Use Checkboxes on the front end. Have a service/repository to save the user data. Something like the following:
public void UpdateUserAnimals(Guid userId, string[] animals)
{
using (SqlConnection conn = new SqlConnection("connectionstring..."))
{
using (SqlCommand cmd = new SqlCommand("Insert Into UserAnimals(UserId, Animals) values (#UserId, #Animal)"))
{
conn.Open();
cmd.Parameters.AddWithValue("#UserId", userId);
foreach(string animal in animals)
{
cmd.Parameters.AddWithValue("#Animal", animal);
cmd.ExecuteNonQuery();
}
}
}
}
There are more complex solutions, but this is a simple one.