C# and slow update of System.Data.DataRow in ADO.NET - c#

I'm using ADO.NET in a simple C# application.
There are two tables, TableA and TableB. TableA is a parent of Table B. TableA contains:
id as a primary key (Int32)
Other columns. I think it's irrelevant so I won't elaborate.
Table B has these columns:
id (primary key) (Int32)
tableAid (foreign key relationship with table A) (Int32 and primary key)
X (double type)
Y (double type)
I have created approximately 300 rows in table B. I want to update the columns values for X and Y to have the same value for each row. I'm currently doing this:
TableBRow[] rowsOfB = TableA.GetTableBRows();
for (int i = 0 ; i < rowsOfB.Length ; i++)
{
rowsOfB[i].X = newXvalue;
rowsOfB[i].Y = newYvalue;
}
This code seems to take a long time to run. My questions are (i) why is this slow ? and (ii) what is the recommended way of updating many rows in a table? Is there a bulk update approach.

if you're doing a large update, generally creating a temp table, doing a bulk insert, join on this temp table and do your update is quicker than doing n updates.

Related

Return the row, when Unique key voliation happens

Is it possible to return the record, that causes the unique key violation in MSSQL, When inserting data?
Try this schema
select * from
(
--query used for your insert
) f1
where exists
(
select * from tablewhereyouwantinsert f2
where f1.key1=f2.key1 and f1.key2=f2.key2 ---- keys used into your unique key violation
)
You can use MERGE to conditionally insert or retrieve a row from the database using a single statement.
Unfortunately, to get the retrieval action, we do have to touch the existing row, I'm assuming that's acceptable and that you'll be able to construct a low impact "No-Op" UPDATE as below:
create table T (ID int not null primary key, Col1 varchar(3) not null)
insert into T(ID,Col1) values (1,'abc')
;merge T t
using (values (1,'def')) s(ID,Col1)
on t.ID = s.ID
when matched then update set Col1 = t.Col1
when not matched then insert (ID,Col1) values (s.ID,s.Col1)
output inserted.*,$action;
This produces:
ID Col1 $action
----------- ---- ----------
1 abc UPDATE
Including the $action column helps you know that this was an existing row rather than the insert of (1,def) succeeding.

Compare two DataTables with several keys and select the rows that are not present in second table

I have two DataTables and I want to select the rows from the first one which are not present in second one, both tables have 3 Keys custnum, shiptonum, connum
For example:
Table Contacts
custnum shiptonum connum column
1 1 1 data1
2 2 2 data2
3 3 3 data3
4 4 4 data4
Table Invitations
custnum shiptonum connum column
1 1 1 data11
3 3 3 data33
I'd like the result to be:
Table Result
custnum shiptonum connum column
2 2 2 data2
4 4 4 data4
I already tried using
var differences = table1.AsEnumerable().Except(table2.AsEnumerable(),DataRowComparer.Default);
but it didn't work. For example in my testing in Contacts table I have 14,389 records, in Invitations table I have two records that exist in Contacts table the count after using the abovesolution was 14,389 instead of 14,387 (removing the two records from Invitations table).
You wrote:
I want to select the rows from the first one which are not present in second one
From your example, I see that you don't want to select rows from the first table that are not rows in the second table, but that you only want to take the values of the keys into account:
I want to select all rows from tableA which have keys with values that are not keys from tableB
You didn't define your tables. They might be IQueryable, or IEnumerable, for your LINQ statements there is not a big difference. Try to avoid AsEnumerable, especially if your data source is in a different process, like a database management system. The other process is much more efficient in executing your query than your process. AsEnumerable transports all data from your other process to your process, which is a relatively slow process. Therefore as a rule: Only use AsEnumerable this if you really need to,
The second definition defines clearer what you want: apparently from tableB you only need the keys:
var keysTableB = tableB.Select(row => new
{
CustNum = row.custNum,
ShipToNum = row.shiptonum,
ConNum = row.connum,
});
In words: from every row in tableB make one new object of anonymous type with three properties: CustNum, ShipToNum and ConNum
Select uses lazy execution. No query is executed, only property Expression is changed.
Now you want to keep only the rows from tableA that have a key that is a member of sequence keysTableB: if you want to keep a subset of a sequence, use Where
var result = tableA.Where(row => keysTableB.Contains(new
{
CustNum = row.custNum,
ShipToNum = row.shiptonum,
Connum = row.connum,
}));
In words: from every row in tableB keep only those rows that have a key that is also in keysTableB, using value equality.
TODO: consider concatenating these two LINQ statements into one.I doubt whether this would improve performance. It surely will deteriorate readability of your code, and thus decreases changeability / maintenance / testability.
for (int i=0;i<table1.rows.count;i++)
{
var rowExists = from dr in table2.AsEnumerable()
where dr.Field<typeofcolumn>("colum_name")==table1.Rows[i]["column_name"]
select dr;
if(rowExists.ToList().Count==0)
{
//here u import row table1.rows[i] to new table
}
}

Create SQLite Database From Other SQLite Database C#

I have an SQLite database which a set of tables. All data in these tables can be isolated into a groups of sets by some id. For example:
Table A
ID value1 value2
1 asd fgh
2 sdf ghj
Table B
ID ID2 value4
1 10 vbn
2 11 bnm
Table C
ID2 value5 value6
10 asdfg qwer
11 tyui hjkl
Where each ID column will map the other ID and each ID2 will map to the other ID2.
I want to take this database, and generate a series of smaller databases, each of which have the same structure, but will only contain data from 1 ID:
Database1.sqlite
Table A
ID value1 value2
1 asd fgh
Table B
ID ID2 value4
1 10 vbn
Table C
ID2 value5 value6
10 asdfg qwer
Database2.sqlite
Table A
ID value1 value2
2 sdf ghj
Table B
ID ID2 value4
2 11 bnm
Table C
ID2 value5 value6
11 tyui hjkl
I could just create the tables one by one, gather all data per ID through a series of SELECT statements, then add it through a series of INSERT statements, but I think there has to be a better way.
My other idea is that I can create a series of views, each of which isolates the data into the format above. From there, I could just write these series of views an sqlite file as a database.
My question is how realistic is my view generation idea? Would it be possible to generate a series of views that mimic each table's structure, but for say where ID = 1 and then save those views as an sqlite file? All of this will need to be done in C#. Is there a better way to do what I am trying to do?
Some More Info
These tables can have multiple rows with the same IDs. There will also need to be some primary key / foreign keys for each table. Ideally, we could then take these smaller tables, and then compress them all into a larger table in the future.
It is possible to combine INSERT and SELECT.
Together with ATTACHed databases, this allows to do the copying with one statement per table:
ATTACH 'C:\some\where\Database1.sqlite' AS db1;
CREATE TABLE db1.A(ID, value1, value2);
CREATE TABLE db1.B(ID, ID2, value4);
CREATE TABLE db1.C(ID2, value5, value6);
INSERT INTO db1.A SELECT * FROM main.A WHERE ID = 1;
INSERT INTO db1.B SELECT * FROM main.B WHERE ID = 1;
INSERT INTO db1.C SELECT * FROM main.C
WHERE ID2 IN (SELECT ID2 FROM B WHERE ID = 1);
ATTACH 'C:\some\where\Database2.sqlite' AS db2;
CREATE TABLE db2.A(ID, value1, value2);
CREATE TABLE db2.B(ID, ID2, value4);
CREATE TABLE db2.C(ID2, value5, value6);
INSERT INTO db2.A SELECT * FROM main.A WHERE ID = 2;
INSERT INTO db2.B SELECT * FROM main.B WHERE ID = 2;
INSERT INTO db2.C SELECT * FROM main.C
WHERE ID2 IN (SELECT ID2 FROM B WHERE ID = 2);

Compare datatables with unlike primary keys

I have datatables A and B. Table A has columns 1 and 2. Columns 1 and 2 are the primary key. Table B has columns 1, 2, 4. Columns 1 and 4 are the primary key. I want to update table B so that for every value where B.1 == A.1 I want to make it so that B.2 = A.2. Because 2 is not part of the primary key for table B there may be multiple records where B.1 and B.2 are the same and I want to update 2 for all those rows.
I am stuck at this kind of code:
foreach(DataRow dr in A.Rows){
DataRow Found = B.Rows.Find(dr[1]);
if(Found != null)
Found[2] = dr[2];
}
The major problem I am facing is that because table B has a compound primary key that is shared by table A. The find is looking for two values but only one can come from table A.

Auto-incrementing a number that is part of a string value in a SQL Server database

How can I auto-increment a number that is part of a string value in a SQL Server database?
For example, here is my table:
EMP_ID EMPNAME EMPSECTION
EMP_1 ROSE S-11
EMP_2 JANE R-11
When I add a new record, what I would like to do is automatically increment the number that follows EMP_. For example, EMP_3, EMP_4, etc.
one option is to have a table that has an autoincrement id field. Then you can write a trigger on this table that on insert, fires an insert on the autoincrement table and fetches the current value. Then concat that value on to the end of EMP_
By C# It's very to do , each time you want to insert a new row before inserting that row you should generate the key by following these steps :
1- get a list of your ID field
2- Do a for each loop to find tha maximum key value , something like this :
int maxID=1;
for each(var l in list)
{
if(int.Parse(l.ID.Replace("EMP_",""))>maxID)
{
maxID=int.Parse(l.ID.Replace("EMP_",""));
}
}
maxID=maxID+1;
string ID="EMP_"+maxID.Tostring();
And ID is your new ID !
but if your application is accessed by multiple programs (example : consider It's a website) I really don't suggest you to do something like this cause : 1. It's time consuming 2. In some condition same key value from multiple clients might be generated and you will have error while inserting .
You can have identity column in your table and display 'EMP_' appended to its value in your user interface. If you want to do it custom way, you'll need a sequence table
Create a sequence table
Sequence
-------------------
Seq_Name | Seq_Val
-------------------
EMPLOYEE | 0
Then you need a Stored Procedure to perform this
BEGIN
declare #curVal int
Select #curVal = Seq_Val+1 From Sequence Where Seq_Name='EMPLOYEE'
UPDATE Sequence SET Seq_Val = Seq_Val+1 Where Seq_Name='EMPLOYEE'
Insert into Employee Values ('EMP_'+Cast(#curVal As Varchar), 'Rose', 'S-11')
END
You can do something like:
create table dbo.foo
(
id int not null identity(1,1) , -- actual primary key
.
.
.
formatted_id as 'emp_' + convert(varchar,id) , -- surrogate/alternate key
constraint foo_PK primary key ( id ) ,
constraint foo_AK01 unique ( formatted_id ) ,
)
But I can't for the life of me think of just why one might want to do that.

Categories