Accessing two databases using Data Reader - c#

I am trying to develop an application using ADO.NET. I have two tables in two different databases. Each of them have a portion of the complete data. Now I need to write a query such that I am able to fetch the complete record from the two tables. As an example say table 1 has Index_no,emp_ID and contact no. Table 2 has index_no, emp_name, salary and dept. The index_no is same for the same record portion in each table.
Following is the code to fetch all records where salary <20000.
sqlCmd2 = new SqlCommand("SELECT * FROM table1 WHERE Index_No =#Index_No",
TestCon);
int i = 0;
while (reader.Read()) {
ListBox1.Items.Add(reader.GetInt32(0) + " - " +
reader.GetString(1) + " - " + reader.GetString(2));
// Name.Text += reader["Name"] + "<br />"; ;
// Depart.Text += reader["Depart"] + "<br />"; ;
array1[i] = reader.GetInt32(0);
i++;
}
sqlCmd2.Parameters.Add("#Index_No", System.Data.SqlDbType.Decimal);
i = 0;
do {
sqlCmd2.Parameters["#Index_No"].Value = array1[i];
reader1 = sqlCmd2.ExecuteReader();
reader1.Read();
ListBox2.Items.Add(reader1.GetString(1));
i++;
} while (i < array1.Length);
The problem with this is that I am getting only one record info from table2 while for table 1 I get all the desired record info. The do-while loop seems to terminate after one iteration only.

It depends, what two different databases means. If the two databases run on the same SQL-Server, it is easy to access the table of the other database
SELECT * FROM OtherDb.dbo.TableOnOtherDb
If not, I would suggest you to create a database link between the two databases (see SO question How do I create and query linked database servers in SQL Server?). Then you can access the other table as above.
In both cases you can use a JOIN query to join the two tables. Then you will need only one data reader
SELECT
A.Index_no, A.emp_ID, A.contact_no,
B.emp_name, B.salary, B.dept
FROM
table1 A
INNER JOIN table2 B
ON A.Index_no = B.Index_no
WHERE
B.salary < 20000
ORDER BY
B.emp_name
UPDATE
If the number of involved records is small, then querying the second table only once by using a IN clause would be far more efficient, if you cannot link the two servers for some reason.
SELECT *
FROM table1
WHERE Index_no IN (4,12,17,30,112,167)
You would create this SQL statement like this
string[] stringArray = array1
.Select(i => i.ToString())
.ToArray();
string list = String.Join(",", stringArray);
string sql = "SELECT * FROM table1 WHERE Index_No IN (" + list + ")";
The idiomatic way of doing the second loop would be (not do while)
for (int i = 0; i < array1.Length; i++) {
...
}

Why don't you write a stored procedure which joins both the ables and gives back the results? You can connect to the second db using linked server or you can refer the second table using the dbname.tablename format.

Related

How to get data without conditions in C#

Hi. I have 2 data tables like this:
I want to get the ID in Table1 if the User in Table2 exists or does not exist
This is the code I test and get the data:
string idGet = "";
string getValue = "Select ID, Port, User from Table1";
DataTable dtgetValue = XLDL.ReadTable(getValue);
if(dtgetValue.Rows.Count > 0)
{
List<ListOtherUser> listOtherUser = new List<ListOtherUser>();
for (int i = 0; i < dtgetValue.Rows.Count; i++)
{
listOtherUser.Add(new ListOtherUser { ID = dtgetValue.Rows[i]["ID"].ToString(), User = dtgetValue.Rows[i]["User"].ToString(), Port = dtgetValue.Rows[i]["Port"].ToString() });
}
foreach (var itemuser in listOtherUser)
{
string checkUser = "Select ID from Table2 where User = N'" + itemuser.User + "'";
DataTable dtcheckUser = XLDL.ReadTable(checkUser);
if (dtcheckUser.Rows.Count > 0)
{
idGet += itemuser.ID + ",";
}
else
{
//Here I want to continue to get the data of row ID=3 from Table1. However I don't know how to solve it?
}
}
}
As the data above I want the output as: idGet = 1 and 3 from Table1
With data from Table1 and Table2:
As the data above I want the output as: idGet = 2 and 3 from Table1
Looking forward to a solution from everyone. Thank you!
The best solution here though would be to do some SQL joins and exclude it coming in, but if you want a solution in code instead, depdending on how large that dataset is/will be, this is a good spot for LINQ.
var result = Table2.Where(p => table1.All(p2 => p2.UserID != p.UserID));
Adapted from this question.
If you opted for SQL, your query would look something more like this and while looking at your logic, you should absolutely not do that how you are trying to. That is so many single db calls for absolutely no reason.
Select Table1.ID
FROM Table1 LEFT OUTER JOIN
Table2 ON Table1.User = Table2.User
WHERE Table2.ID IS NULL;

Compare a list in C# to a table in a database

I need to compare a list of sequential integers created from a C# Windows Form to a database table of integers, indicating if there are duplicates.
I have a version that works, below, but I'm assuming it's probably the least efficient way of doing this - comparing the C# list one by one to each integer in the database table.
Should I get the integers from the database into C#, and then compare? Or is there a sql way of asking:
if any item in list A is contained in list B, etc.... without comparing each number one-by-one?
I've seen lots of opinions on just looking for 1 item in a database, but I need an efficient way of comparing C# lists of sometimes 5,000 or more to a database table that can end up having hundreds of thousands of records.
public static string VerifyManufacturingSerialOnly(int count, int beginning)
{
string duplicateSerials = "";
int currentSerial = beginning;
for (int i = 0; i < count; i++)
{
OleDbConnection connection = BadgeDatabaseDB.GetConnection();
string checkStatement
= "SELECT * "
+ "FROM SerialNumbersMFG "
+ "WHERE SerialNumber = #CurrentSerial";
OleDbCommand command =
new OleDbCommand(checkStatement, connection);
command.Parameters.AddWithValue("#CurrentSerial", currentSerial);
try
{
connection.Open();
OleDbDataReader dataReader =
command.ExecuteReader(CommandBehavior.SingleRow);
if (dataReader.Read())
{
duplicateSerials +=
"Serial # " +
currentSerial +
" already exists in order # " +
dataReader["OrderNumber"].ToString() + "\n";
}
else { }
}
catch (OleDbException ex)
{
throw ex;
}
finally
{
connection.Close();
}
currentSerial++;
i++;
}
return duplicateSerials;
Two ways:
Get all the id's from the database SELECT SerialNumber FROM SerialNumbersMFG and then you can use linq list1.Intersect(list2)
As posted in the comment, most DB have the IN clause, so you can use the query like: SELECTSerialNumber FROM SerialNumbersMFG WHERE SerialNumber IN (1,2,3...) which will also do the required thing.
Since you mention that the DB can have hundreds of thousand of record I would suggest that second way is better. Please use stringbuilder for concatenation.

Build Where Clause Dynamically in Ado.net C#

I will be taking in around 1000 records at a given time and I have to determine if they are existing records or new records.
If they are existing I have to update the records, if new then just insert them. I will not know if any of them will be existing or if they all will be existing.
I thought that it might be best to do one query to the database and try to find if any of them exist in the db and store them in memory and check that collection in memory and check that.
Originally I was told I 1 field would be enough to determine uniqueness. So I thought I could just do 1 big in clause against 1 field in the database but now I found out that is not the case and I need to use 3 fields to determine if the record is existing or now.
This is basically an and clause
select * from where columnA = "1" and ColumnB = "2" and ColumnC = "3"
How can I properly right this in C# ado.net?
I am guessing I going to need to have like some super where clause?
select * from where (columnA = "1" and ColumnB = "2" and ColumnC = "3") or (columnA = "4" and ColumnB = "5" and ColumnC = "6") or [....998 more conditional clauses)
I am open to better ideas if possible. I still think doing it in 1 shot is better than doing 1000 separate queries.
I can only help you to write query for your request
var recordCount = 1000;
var query = "SELECT * FROM TableName WHERE";
for (var i = 1; i < recordCount - 2; i += 3)
{
query += " (columnA = " + i + " and ColumnB = " + (i + 1) + " and ColumnC = " + (i + 2) + ") or ";
}
I feel kinda silly writing this answer, because I think that you should be able to put the pieces together a complete answer from other posts - but this is not an exact duplicate of either of the questions I have in mind.
There already are questions and answers in Stackoverflow dealing with this issue - however in my search I only found answers that are not thread safe, and most of them are using merge.
There are different questions and answers I can refer you to such as
my answer to Adding multiple parameterized variables to a database in c#
where you can see how to work with table valued parameters on c#, and to Aaron Bertrand's answer to Using a if condition in an insert SQL Server where you can see how to create a safe upsert - however I didn't find any answer that covers this completely - so here you go:
First you need to create a user defined table type in your database:
CERATE TYPE MyTableType AS TABLE
(
Column1 int NOT NULL,
Column2 int NOT NULL,
Column3 int NOT NULL,
-- rest of the columns in your table goes here
PRIMARY KEY (Column1, Column2, Column3)
)
Then, you create the stored procedure:
CREATE stp_UpsertMyTable
(
#MyTableType dbo.MyTableType readonly -- table valued parameters must be readonly
)
AS
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
UPDATE t
SET t.column4 = tvp.column4,
t.column5 = tvp.column5 -- and so on for all columns that are not part of the key
FROM dbo.MyTable AS t
INNER JOIN #MyTableType AS tvp
ON t.Column1 = tvp.Column1
AND t.Column2 = tvp.Column2
AND t.Column3 = tvp.Column3;
-- Note: <ColumnsList> should be replaced with the actual columns in the table
INSERT dbo.MyTable(<ColumnsList>)
SELECT <ColumnsList>
FROM #MyTableType AS tvp
WHERE NOT EXISTS
(
SELECT 1 FROM dbo.MyTable t
WHERE t.Column1 = tvp.Column1
AND t.Column2 = tvp.Column2
AND t.Column3 = tvp.Column3
);
COMMIT TRANSACTION;
GO
Then, the c# part is simple:
DataTable dt = new DataTable();
dt.Columns.Add("Column1", typeof(int));
dt.Columns.Add("Column2", typeof(int));
dt.Columns.Add("Column3", typeof(int));
dt.Columns.Add("Column4", typeof(string));
dt.Columns.Add("Column5", typeof(string));
// Fill your data table here
using (var con = new SqlConnection("ConnectionString"))
{
using(var cmd = new SqlCommand("stp_UpsertMyTable", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#MyTable", SqlDbType.Structured).Value = dt;
con.Open();
cmd.ExecuteNonQuery();
}
}
Now you have a complete and safe upsert using a table valued parameter with only one round trip between c# and sql server.

Insert from One MS Access database to Another MS Access database

I have to take the data from MS Access DB to another.
This was insert statement used
cmd.CommandText = #"Insert Into [MS Access;PWD=pw;DATABASE=" + currentDBPath + #"].[Orders] Select * FROM [Orders] where OrderDate>=#" + from.ToShortDateString() + "# and OrderDate <=#" + to.ToShortDateString() + "# and IsCustomer=Yes ";
This statement works fine. But some one started to enter the data directly to target database and also in the source. This created duplicated records. Now I want to copy those orders from source which are not in the target DB's table.
Assuming Orders table has a primary key named IDOrers, you must bring both tables to one DB, so you can compare data.
Easy option: have in Sours DB a link to [Orders] on Destination DB, named OrdersDest. In that case you create on destination a query of missing orders, named MissingOrders :
SELECT Orders.* FROM Orders LEFT JOIN OrdersDest ON OrdersDest.IDOrders = Orders.IDOrders WHERE OrdersDest.IDOrders Is Null
Your Command will now look like this:
cmd.CommandText = #"Insert Into [MS Access;PWD=pw;DATABASE=" + currentDBPath + #"].[Orders] Select * FROM [MissingOrders] where OrderDate>=#" + from.ToShortDateString() + "# and OrderDate <=#" + to.ToShortDateString() + "# and IsCustomer=Yes ";
You could also pass the data through this linked table:
cmd.CommandText = #"Insert Into [OrdersDest] Select * FROM [MissingOrders] where OrderDate>=#" + from.ToShortDateString() + "# and OrderDate <=#" + to.ToShortDateString() + "# and IsCustomer=Yes ";
I didn't find any solution to what I was looking for in my question , So I decided to just delete the duplicated data in destination database.
I used the below statement to delete the data ,
Delete * from Orders where AutoOrderID in (SELECT Orders.AutoOrderID FROM Orders Inner JOIN OrdersSource ON OrdersSource .OrderId = Orders.OrderId and OrdersSource .OrderDate=Orders.OrderDate);

How to copy data from two different table and insert fetched records into another table

I am trying to insert data in my table which have 3 feild
(1) sendReqID type int(PK)
(2) RequestID type int (FK from table Request)
(3) DonorID type int (FK table Donor)
I know how to copy data from one table and insert into another table but I want to know how to insert data in table, when we have to extract values from two different tables. Following is my code which I am trying and unable to insert data into my table.
public void Req_SendID()
{
SqlConnection MySQL = new SqlConnection(ConfigurationManager.ConnectionStrings["RegistrationConnectionString"].ToString());
string copy = "insert into Send_Request(RequestID,DonorID) Select RequestID,DonorID from RequestID and DonorID from Donor where R_City='" + Session["BGroup"] + "' and" + "D_City='" + Session["city"] + "'";
SqlCommand com = new SqlCommand(copy, MySQL);
MySQL.Open();
com.ExecuteNonQuery();
MySQL.Close();
}
Please Help thanks in advance.
You need to join on the two tables...
insert into Send_Request(RequestID,DonorID)
Select r.RequestID, d.DonorID
from RequestID r inner join Donor d ON r.R_City = d.D_City
where R_City='" + Session["BGroup"] + "' and " + "D_City='" + Session["city"] + "'"
I'm assuming the relationship is as above. However, consider SQL Injection attacks and look to parametrize your query.
EDIT: Using Parameterized Query
var requestCity = Session["BGroup"].ToString();
var donorCity = Session["city"].ToString();
"insert into Send_Request(RequestID,DonorID)
Select r.RequestID, d.DonorID
from RequestID r inner join Donor d ON r.R_City = d.D_City
where R_City=#RequestCity and D_City=#DonorCity"
SqlCommand com = new SqlCommand(copy, MySQL);
com.Parameters.Add("#RequestCity", requestCity);
com.Parameters.Add("#DonorCity", donorCity);
....
However, I just saw your comment that there is no relationship between the tables, so the actual query above would be incorrect.

Categories