SELECT and update the row in DataTable - c#

I have a following SQL statement and would like to update Database table if row found.
string sql = "Select A.CNum FROM TABLEA A, TABLEB B WHERE A.CID= B.CID AND A.CNum is NULL AND CID=#cID"
DataTable dt = querySql(sql, params);
if (dt.Rows.Count > 0)
{
// I would like to update CNum from TableA
}
What is the best method to update the row from SQL Statement?
Thank you..

It should be possible to do this in one statement without round-tripping any data from the database and back:
UPDATE
TABLEA
SET
CNum = newValueHere
FROM
TABLEA A,
INNER JOIN TABLEB B ON B.CID = A.CID
WHERE
A.CNum is NULL
AND A.CID=#cID
note I qualified the CID reference in the last line ( I think you'll get an error without this as it exists on both tables, and used an inner join to connect your tables. Note that newValueHere can be an expression of any of the columns in A or B.

Using the SQL from Tom's answer with the following C# will give you what you want.
using(SqlCommand cmd = new SqlCommand(sql, conection))
{
int rowsAffected = cmd.ExecuteNonQuery();
}

you can use EXISTS construct to do this in just one query.
string sql = "IF EXISTS(Select A.CNum FROM TABLEA A, TABLEB B WHERE A.CID= B.CID AND A.CNum is NULL AND CID=#cID) BEGIN ..... END"

Related

Inner join two table variables and return an output cursor from an anonymous plsql block in a c# application

I have this scenario:
I need to insert the result of many joins (15 tables with various filters) into a table variable var_TB_PROJECT
Then insert the result of many other joins (8 tables with various filters) into another table variable var_TB_CAMERAS
Finally, inner join these two table variables
All this inside an anonymous plsql block, since I can't create any objects in the source database (no privileges).
This anonymous plsql block will be executed inside a C# application that will return an output cursor as sample code below.
Is it possible to do that ?
static void TestBlock()
{
string conString = ConfigManager.GetConnectionStringByName("CI_L3");
OracleConnection con = new OracleConnection();
con.ConnectionString = conString;
con.Open();
string cmdtxt = #"
DECLARE
type rectyp is record(TABLE1.FIELD1%TYPE, TABLE2.FIELD1%TYPE, TABLE3.FIELD1%TYPE, ... many fields .... );
type tpTbl is table of rectyp;
var_TB_PROJETO tpTbl;
var_TB_CAMERAS tpTbl;
BEGIN
-- load var_TB_PROJETO
select FIELD1, FIEL2, FIELN .... bulk collect into var_TB_PROJETO
from TABLE1 INNER JOIN TABLE2 ON TABLE1.ID = TABLE2.FID
INNER JOIN TABLE3 ON TABLE2.ID = TABLE3.FID ....
.
.
-- many tables ...
.
.
-- load var_TB_CAMERAS
select FIELD1, FIEL2, FIELN .... bulk collect into var_TB_CAMERAS
from TABLE1 INNER JOIN TABLE2 ON TABLE1.ID = TABLE2.FID
INNER JOIN TABLE3 ON TABLE2.ID = TABLE3.FID ....
.
.
-- many tables ...
.
.
OPEN :1 for SELECT * FROM var_TB_PROJETO INNER JOIN var_TB_CAMERAS
ON var_TB_PROJETO.ID = var_TB_CAMERAS.ID;
END;";
OracleCommand cmd = con.CreateCommand();
cmd.CommandText = cmdtxt;
OracleParameter p1 = cmd.Parameters.Add("refcursor1", OracleDbType.RefCursor);
p1.Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
OracleDataReader dr1 = ((OracleRefCursor)cmd.Parameters[0].Value).GetDataReader();
while (dr1.Read()) {
var st1 = dr1.GetString(0);
}
}
#Goldar: Why use an anonymous PL/SQL block, when it can be solved as an SQL statement
WITH TB_PROJETO as (
select TABLE1.ID, FIELD1, FIEL2, FIELN
from TABLE1 INNER JOIN TABLE2 ON TABLE1.ID = TABLE2.FID
INNER JOIN TABLE3 ON TABLE2.ID = TABLE3.FID ....
.
.
-- many tables ...
.
.
), TB_CAMERAS as (
select TABLE1.ID, FIELD1, FIEL2, FIELN
from TABLE1 INNER JOIN TABLE2 ON TABLE1.ID = TABLE2.FID
INNER JOIN TABLE3 ON TABLE2.ID = TABLE3.FID ....
.
.
-- many tables ...
.
.
)
SELECT *
FROM TB_PROJETO
INNER JOIN TB_CAMERAS ON TB_PROJETO.ID = TB_CAMERAS.ID;

Optimize SQL function in C# code

I'm running into an issue with an application that's leading me to a method doing the following.
protected override int GetCount(List<int> itemlist)
{
sql.Execute(#"TRUNCATE Table table0");
int count = 0;
foreach (int itemgroup in itemlist)
{
count += sql.Execute(#" INSERT INTO table0 (ID, Guid)
SELECT table1.ID , table1.Guid
FROM dbo.tablefunction(#p0) table1 LEFT JOIN
dbo.table0 ON table1.ID = table0.ID
WHERE table0.ID IS NULL", itemgroup);
}
return count;
}
i'm running into a key constraint issue during the insert loop which isn't completely unexpected.
But I'm also noticing that it's potentially doing multiple varied size inserts so I'm looking for ideas/suggestions on dynamically assembling a union query and then inserting all results at once. For example,the resulting query might be
WITH b AS
(
SELECT table1.ID , table1.Guid
FROM dbo.tablefunction(item0) table1 LEFT JOIN
dbo.table0 ON table1.ID = table0.ID
WHERE table0.ID IS NULL
UNION
SELECT table1.ID , table1.Guid
FROM dbo.tablefunction(item1) table1 LEFT JOIN
dbo.table0 ON table1.ID = table0.ID
WHERE table0.ID IS NULL
)
INSERT INTO table0 (ID, Guid)
SELECT * FROM b
I'm just not sure how best to go about it.
Use string.format() method :
protected override int GetCount(List<int> itemlist)
{
sql.Execute(#"TRUNCATE Table table0");
int count = 0;
foreach (int itemgroup in itemlist)
{
string sql = string.Format(#" INSERT INTO table0 (ID, Guid)
SELECT table1.ID , table1.Guid
FROM dbo.tablefunction({0}) table1 LEFT JOIN
dbo.table0 ON table1.ID = table0.ID
WHERE table0.ID IS NULL", itemgroup);
count += sql.Execute(sql);
}
return count;
}
You could use Table-Valued Parameters - msdn and a stored procedure to do this.
First, you would need to create a table type to use with the procedure:
create type dbo.ItemGroups_udt as table (ItemGroup int not null);
go
Then, create the procedure:
create procedure dbo.table0_truncate_and_insert (
#ItemGroups as dbo.ItemGroups_udt readonly
) as
begin;
set nocount, xact_abort on;
truncate table table0;
insert into table0 (id, guid)
select tvf.id, tvf.guid
from #ItemGroups as i
cross apply dbo.tablefunction(i.ItemGroup) as tvf;
end;
go
If you run in to constraint violoations then distinct, group by, or other conditions may be necessary
Then, assemble and pass the list of item groups to the stored procedure using a DataTable added as a SqlParameter using SqlDbType.Structured.
Table Valued Parameter Reference:
SQL Server 2008 Table-Valued Parameters and C# Custom Iterators: A Match Made In Heaven! - Leonard Lobel
Table Value Parameter Use With C# - Jignesh Trivedi
Using Table-Valued Parameters in SQL Server and .NET - Erland Sommarskog
Maximizing Performance with Table-Valued Parameters - Dan Guzman
Maximizing throughput with tvp - sqlcat
How to use TVPs with Entity Framework 4.1 and CodeFirst
This is what I ended up coming up with. I may have been pre-coffee earlier when I was looking at this. It could probably still use a little work but it should work.
protected override int GetCount(List<int> itemlist)
{
sql.Execute(#"TRUNCATE Table table0");
int count = 0;
string sql = #"WITH b AS
(
{0}
)
INSERT INTO table0 (ID, Guid)
SELECT ID, Guid
FROM b";
List<string> sqlsubs = new List<string>();
foreach (int itemgroup in itemlist)
{
sqlsub.Add( string.Format(#"SELECT table1.ID , table1.Guid
FROM dbo.tablefunction({0}) table1 LEFT JOIN
dbo.table0 ON table1.ID = table0.ID
WHERE table0.ID IS NULL", itemgroup));
}
string sqlunion = string.Join(" UNION ", sqlsub);
return context.Execute(string.Format(sql, sqlunion));
}

Using COUNT For Comparison in SQL Server CE 4.0

I'm attempting to combine the logic for some of my SQL queries, and I can't seem to figure out this problem. Obviously SQL Server CE has many limitations compared to SQL Server or mySQL, but surely there's a way to solve this.
I want to do a count on one table in my database, based on some parameters, and then I want to compare this value to a value stored in a column in another table.
Let's say the database is modeled like this:
Table1:
ID int
Key string
NumberInUse int
Table2:
ID int
OtherID int
Here's the necessary parts of the query.
SELECT *
FROM Table1
LEFT JOIN Table2 ON Table1.ID = Table2.ID
WHERE Table1.Key = #key
AND (SELECT COUNT(*) FROM Table2 WHERE ID = Table1.ID AND OtherID = #otherID) < Table1.NumberInUse;
Unfortunately this query gives me this error:
There was an error parsing the query. [ Token line number = 4,Token line offset = 6,Token in error = SELECT ]`
So is there a way I can rephrase the WHERE clause of my query to utilize this comparison?
Try this:
SELECT *
FROM Table1 t1
INNER JOIN (SELECT ID
,COUNT(*) numCount
FROM Table2 t2
WHERE t2.OtherId = #otherID
GROUP BY ID) t3
ON t1.ID = t3.ID
WHERE t1.Key = #Key
AND t3.numCount < t1.NumberInUse
Sure it's not SQL. You're missing the right operand of the second LEFT JOIN:
SELECT *
FROM Table1 LEFT JOIN Table2
ON Table1.ID = Table2.ID
LEFT JOIN ????? WHUT ?????
WHERE Table1.Key = #key
AND (SELECT COUNT(*) FROM Table2 WHERE ID = Table1.ID AND OtherID = #otherID) < Table1.NumberInUse;

asp.net multiple table update statement

I need to turn this query into an update statement. I will have to update the values from fields. Everything is already in place but the update statement.
Here is the select version of the query:
SELECT i.GoLiveDate, i.FirstBonusRun, i.TechFName, i.TechLName, i.TechEmail, i.TechPhone, i.WebISPFName, i.WebISPLName,
i.WebISPEmail, i.WebISPPhone, i.FullFillFName, i.FullFillLName, i.FullFillEmail, i.FullFillPhone, d.FName,
d.LName, d.HomePhone, d.Email
FROM NC_Information i
INNER JOIN Distributor d
ON d.DistID = i.ClientID
WHERE clientID = #value
Is it possible to update two different tables from within the same query?
Here is the code I have so far:
public void Update (int ClientID)
{
using ( var conn = new SqlConnection( GeneralFunctions.GetConnectionString() ) )
using ( var cmd = conn.CreateCommand() )
{
conn.Open();
cmd.CommandText =
#"SELECT i.GoLiveDate, i.FirstBonusRun, i.TechFName, i.TechLName, i.TechEmail, i.TechPhone, i.WebISPFName, i.WebISPLName,
i.WebISPEmail, i.WebISPPhone, i.FullFillFName, i.FullFillLName, i.FullFillEmail, i.FullFillPhone, d.FName,
d.LName, d.HomePhone, d.Email
FROM NC_Information i
INNER JOIN Distributor d
ON d.DistID = i.ClientID
WHERE clientID = #value";
cmd.Parameters.AddWithValue( "#value", ClientID );
cmd.ExecuteNonQuery();
}
}
You can't update multiple tables in one statement, but you can use a transaction to make sure that the updates are contingent upon one another:
BEGIN TRANSACTION
UPDATE SomeTable
SET SomeColumn = 'Foo'
WHERE SomeID = 123
UPDATE AnotherTable
SET AnotherColumn = 'Bar'
WHERE AnotherID = 456
COMMIT
I think, you cannot directly do the update on two tables. But you can Optimize the query.
How?
OUTPUT keyword in Insert/Update/Delete Statement
The first Update Statement's Select Data(filtered data) can be reused using the below mentioned example.
CREATE TABLE #table1
(
id INT,
employee VARCHAR(32)
)
go
INSERT INTO #table1 VALUES
(1, 'name1')
,(2, 'name2')
,(3, 'name3')
,(4, 'name4');
GO
DECLARE #GuestTable TABLE
(
id INT,
employee VARCHAR(32)
);
update #table1
Set id = 33
OUTPUT inserted.* INTO #GuestTable
Where id = 3
The Data in the '#GuestTable' Table is filtered data and can be
reused.
select * from #GuestTable
drop table #table1
Alternatively, you can create a dataset with two datatables, and let the tableadaptermanager manage the updates.

C# datatable from sql join 2 columns same name

I have a sql select like so which returns a datatable:
select * from table1 a join table2 b on a.id=b.id
Both table1 and table2 have a column named itemno .
How do i reference the 2 separate columns? Normally I would use something like:
datarow["itemno"].ToString(); <=first column named itemno only
datarow["b.itemno"].ToString(); <= fail
However this only seems to get the first column named itemno.
Is there a way to reference the second column named itemno without changing my sql statement? (I know i can change my sql statement, take out the * and put in column aliases).
You can reference the columns by index instead:
datarow[0].ToString();
I'd much prefer aliasing them though to be honest.
Given an SQL query like this
select a.id, b.id, a.columnA,a.columnB,a.itemno,b.itemno
from table1 a
join table2 b on a.id=b.id
Your C# code would/could look like this to read all rows and all columns:
using (SqlCommand getAllColumns = new SqlCommand("select a.id, b.id,a.columnA,a.columnB,a.itemno,b.itemno from table1 a join table2 b on a.id=b.id", conn))
{
using (var drreader = getAllColumns.ExecuteReader())
{
DataTable tb = new DataTable();
tb.BeginLoadData();
tb.Load(drreader);
tb.EndLoadData();
foreach(DataRow row in tb.Rows.Cast<DataRow>().ToList())
{
// assuming these are all varchar columns
string idA = (string)row["id"];
string idB = (string)row["id1"];
string columnA = (string)row["columnA"];
string columnB = (string)row["columnB"];
string columnAItemNo = (string)row["itemno"]; //fetches the first itemno column, a.itemno in this case
string columnBItemNo = (string)row["itemno1"]; //fetches the second itemno column, b.itemno in this case
}
}
}
I use this on .NET Framework 4.5. If you want to verify or debug this, put a breakpoint on the foreach line and inspect the DataTable object. The second itemno column should be titled differently compared to the first one.

Categories