I am having SQL query like this (will be parametrized once I make this work):
using (FbCommand cmd = new FbCommand("SELECT MAGACINID, ROBAID, SUM(KOLICINA) AS GOD" + godina.ToString() + " FROM STAVKA WHERE VRDOK = 13 OR VRDOK = 15 GROUP BY MAGACINID, ROBAID ORDER BY ROBAID", con))
{
using (FbDataAdapter da = new FbDataAdapter(cmd))
{
DataTable tempDT = new DataTable();
if (dt.Rows.Count == 0)
{
da.Fill(dt);
continue;
}
da.Fill(tempDT);
var result = dt.AsEnumerable()
.Join(tempDT.AsEnumerable(),
x => new { field1 = x["MAGACINID"], field2 = x["ROBAID"] },
y => new { field1 = y["MAGACINID"], field2 = y["ROBAID"] },
(x, y) => new {
x,
addYear = y["GOD" + godina.ToString()]
});
dt = LINQResultToDataTable(result);
}
}
And here is LINQResultToDataTable() method
private DataTable LINQResultToDataTable<T>(IEnumerable<T> Linqlist)
{
DataTable dt = new DataTable();
PropertyInfo[] allColumns = null;
if (Linqlist == null) return dt;
foreach (T Record in Linqlist)
{
if (allColumns == null)
{
allColumns = ((Type)Record.GetType()).GetProperties();
// Record at position 0 is whole object and needs to be broke into pieces
// Record at position 1 is new column
foreach (PropertyInfo GetProperty in allColumns)
{
Type colType = GetProperty.PropertyType;
if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition()
== typeof(Nullable<>)))
{
colType = colType.GetGenericArguments()[0];
}
dt.Columns.Add(new DataColumn(GetProperty.Name, colType));
}
}
DataRow dr = dt.NewRow();
foreach (PropertyInfo pinfo in allColumns)
{
dr[pinfo.Name] = pinfo.GetValue(Record, null) == null ? DBNull.Value : pinfo.GetValue
(Record, null);
}
dt.Rows.Add(dr);
}
return dt;
}
First datatable fill is okay and it fills it with these columns:
MagacinID
RobaID
God2021
Now when I try to join new table using linq I should only add God2020 as new column.
Problem is that when I am creating output of linq I cannot tell it to break x object into columns but I need to take it whole so linq result looks like this:
x (this one have ItemArray with all columns)
God2020
And new datatable looks same.
What I tried doing is inside LINQResultToDataTable method to take 0th element of Result and break it into columns, add to datatable, add new one (1st element) and populate it (see comment in that method) but I am stuck and do not know how to do that. Anyone have any solution?
Edit: I made it not clear so here is more explanation.
I have foreach loop which loops through 5 databases and inside that foreach loop is this code.
First database returns these columns
MagacinID
RobaID
God2021
Second
MagacinID
RobaID
God2020
Third
MagacinID
RobaID
God2019
Fourth
MagacinID
RobaID
God2018
Fifth
MagacinID
RobaID
God2017
I want all this merged into one datatable on columns MagacinID AND RobaID like this:
MagacinID
RobaID
God2021
God2020
God2019
God2018
God2017
By Merge, I mean use the DataTable merge, which basically does something like a full outer join on declared PK fields in a datatable, and then makes the merged-into table the result of the join;
var d1 = new DataTable();
d1.Columns.Add("SomeId");
d1.Columns.Add("Col1");
d1.Rows.Add("ID1", "Col1Val1");
d1.Rows.Add("ID2", "Col1Val2");
d1.PrimaryKey = new[] { d1.Columns["SomeId"] };
var d2 = new DataTable();
d2.Columns.Add("SomeId");
d2.Columns.Add("Col2");
d2.Rows.Add("ID1", "Col2Val1");
d2.Rows.Add("ID3", "Col2Val2");
d2.PrimaryKey = new[] { d2.Columns["SomeId"] };
var d3 = new DataTable();
d3.Columns.Add("SomeId");
d3.Columns.Add("Col3");
d3.Rows.Add("ID2", "Col3Val1");
d3.Rows.Add("ID3", "Col3Val2");
d3.PrimaryKey = new[] { d3.Columns["SomeId"] };
d1.Merge(d2, false, MissingSchemaAction.Add);
d1.Merge(d3, false, MissingSchemaAction.Add);
Here's what the above code leads to:
d1 started off with two columns, then during the first Merge it added in a third (Col2), and the values from d2's Col2 were put into d1's Col2, matching on the PK column (SomeId).
Then during the second Merge a fourth column was added to d1 (Col3), and the values out of Col3 in d3 copied into d1.
You'll notice that I deliberately made d2 have different PK values to d1, so not only do new columns get added, but new rows get added too
No new rows were added by this second merge op (d1 already had an ID1, ID2 and ID3)
Related
I have two data tables as shown below.
datatable1:
table1_id(PK) DriverID Vehicle
111 Ram00 VRN01
112 Shyam00 VRN02
113 Ram00 VRN03
datatable2:
table2_id(PK) DriverID exit_time
AA1 Ram00 10.10AM
AA2 Hari00 11.20PM
Combined Output
table1_id DriverID Vehicle table2_id exit_time
111 Ram00 VRN01 AA1 10.10AM
112 Shyam00 VRN02 NULL NULL
113 Ram00 VRN03 AA1 10.10AM
NULL Hari00 NULL AA2 11:20PM
DriverID is common in both table. But just merging two datatable will not give this result.
Please help to achieve this.
datatable1.Merge(datatable2);
You can use Two Data tables to combine into one Data table via Coding and Remove the Extra Column later the For loop ends,Check my code it will work.
string Qry = "select tab1.table_id,'' as DriverID,vehicle,tab1.driver_id Tab1DrvrID,exit_time from tab1 " +
"full join tab2 on tab2.driver_id=tab1.driver_id";
cmd = new SqlCommand(Qry, con);
da = new SqlDataAdapter(cmd);
dt = new DataTable();
da.Fill(dt);
//string DrvrID;
for (int i = 0; i < dt.Rows.Count; i++)
{
string Qry2 = "select tab1.table_id,'' as DriverID,vehicle,tab1.driver_id Tab1DrvrID,tab2.driver_id Tab2DrvrID,exit_time from tab1 " +
"full join tab2 on tab2.driver_id=tab1.driver_id ";
cmd = new SqlCommand(Qry2, con);
SqlDataAdapter daa = new SqlDataAdapter();
DataTable dtt = new DataTable();
daa = new SqlDataAdapter(cmd);
daa.Fill(dtt);
if (dtt.Rows.Count > 0)//
{
string s=dtt.Rows[i]["Tab1DrvrID"].ToString();
if (s=="")
{
dt.Rows[i]["DriverID"] = dtt.Rows[i]["Tab2DrvrID"].ToString();
}
else
{
dt.Rows[i]["DriverID"] = dtt.Rows[i]["Tab1DrvrID"].ToString();
}
}
else
{
}
dt.AcceptChanges();
}
dt.Columns.Remove("Tab1DrvrID");
Merge works properly if columns from two DATATABLES are matched in the same DATATYPE. If the column has a NULL value in the first row of DATATABLE the column DATATYPE will be String. So the second DATATABLE, if have value Date or any other type, will miss the match on merge . To resolve this problem you need to make the two DATATABLES columns same DATATYPE.
private DataTable MergeDataTable(DataTable dataTable1, DataTable dataTable2)
{
var dtCloned = dataTable2.Clone();
foreach (DataColumn column in dataTable2.Columns)
{
var col = dataTable1.Columns[column.ColumnName];
if (col != null && col.DataType != column.DataType )
{
dtCloned.Columns[column.ColumnName].DataType = col.DataType;
}
}
foreach (DataRow d in dataTable2.Rows)
{
dtCloned.ImportRow(d);
}
dataTable1.Merge(dtCloned);
return dataTable1;
}
I have two columns in a datatable:
ID, Calls.
How do I find what the value of Calls is where ID = 5?
5 could be anynumber, its just for example. Each row has a unique ID.
Make a string criteria to search for, like this:
string searchExpression = "ID = 5"
Then use the .Select() method of the DataTable object, like this:
DataRow[] foundRows = YourDataTable.Select(searchExpression);
Now you can loop through the results, like this:
int numberOfCalls;
bool result;
foreach(DataRow dr in foundRows)
{
// Get value of Calls here
result = Int32.TryParse(dr["Calls"], out numberOfCalls);
// Optionally, you can check the result of the attempted try parse here
// and do something if you wish
if(result)
{
// Try parse to 32-bit integer worked
}
else
{
// Try parse to 32-bit integer failed
}
}
You can use LINQ to DataSet/DataTable
var rows = dt.AsEnumerable()
.Where(r=> r.Field<int>("ID") == 5);
Since each row has a unique ID, you should use Single/SingleOrDefault which would throw exception if you get multiple records back.
DataRow dr = dt.AsEnumerable()
.SingleOrDefault(r=> r.Field<int>("ID") == 5);
(Substitute int for the type of your ID field)
I could use the following code.
Thanks everyone.
int intID = 5;
DataTable Dt = MyFuctions.GetData();
Dt.PrimaryKey = new DataColumn[] { Dt.Columns["ID"] };
DataRow Drw = Dt.Rows.Find(intID);
if (Drw != null) Dt.Rows.Remove(Drw);
You can try with method select
DataRow[] rows = table.Select("ID = 7");
DataRow dataRow = dataTable.AsEnumerable().FirstOrDefault(r => Convert.ToInt32(r["ID"]) == 5);
if (dataRow != null)
{
// code
}
If it is a typed DataSet:
MyDatasetType.MyDataTableRow dataRow = dataSet.MyDataTable.FirstOrDefault(r => r.ID == 5);
if (dataRow != null)
{
// code
}
try this code
DataRow foundRow = FinalDt.Rows.Find(Value);
but set at lease one primary key
Hello just create a simple function that looks as shown below.. That returns all rows where the call parameter entered is valid or true.
public DataTable SearchRecords(string Col1, DataTable RecordDT_, int KeyWORD)
{
TempTable = RecordDT_;
DataView DV = new DataView(TempTable);
DV.RowFilter = string.Format(string.Format("Convert({0},'System.String')",Col1) + " LIKE '{0}'", KeyWORD);
return DV.ToTable();
}
and simply call it as shown below;
DataTable RowsFound=SearchRecords("IdColumn", OriginalTable,5);
where 5 is the ID.
Thanks..
Try avoiding unnecessary loops and go for this if needed.
string SearchByColumn = "ColumnName=" + value;
DataRow[] hasRows = currentDataTable.Select(SearchByColumn);
if (hasRows.Length == 0)
{
//your logic goes here
}
else
{
//your logic goes here
}
If you want to search by specific ID then there should be a primary key in a table.
I'm typically used to traditional table in SQL where I have multiple columns with rows populated. I execute a stored procedure and store all the data in DataTable and loop through the table to get the results I need. For example,
public static DataTable getInfo (string sessionID)
{
try
{
SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["SandBox"].ConnectionString);
SqlCommand cmd = new SqlCommand("GetSessionInfo", conn);
cmd.Parameters.AddWithValue("SessionGUID", sessionID);
cmd.CommandType = CommandType.StoredProcedure;
DataTable dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(dt);
return dt;
}
catch (Exception)
{
throw;
}
}
I would load the DataTable:
DataTable infoTbl = new DataTable();
infoTbl = getInfo(lbldatabasesessionID.Text);
And I would use foreach loop to loop through the DataTable.
foreach (DataRow row in infoTbl.Rows)
{
string x = col.ToString();
}
The issue I run into is the database guy gave me a stored procedure that returns a different output (different from what I'm used to). It's a row based.
The only way I can access for example the First Name is if I hard code the position like:
string firstName = infoTbl.Rows[16][2].ToString();
I don't feel comfortable doing this since the position could potentially change. How would I access ElementValue by knowing the name knowing ElementType and ElementName?
Any suggestions?
Using DataSet:
string firstName = string.Empty;
DataRow row = table.Select("ElementType = 'Demographics' AND ElementName = 'FirstName'").FirstOrDefault();
if (row != null)
{
firstName = (string)row["ElementValue"];
}
Using Linq:
string firstName = table.AsEnumerable()
.Where(f => f.Field<string>("ElementType") == "Demographics" &&
f.Field<string>("ElementName") == "FirstName")
.Select(f => f.Field<string>("ElementValue")).FirstOrDefault();
I have two columns in a datatable:
ID, Calls.
How do I find what the value of Calls is where ID = 5?
5 could be anynumber, its just for example. Each row has a unique ID.
Make a string criteria to search for, like this:
string searchExpression = "ID = 5"
Then use the .Select() method of the DataTable object, like this:
DataRow[] foundRows = YourDataTable.Select(searchExpression);
Now you can loop through the results, like this:
int numberOfCalls;
bool result;
foreach(DataRow dr in foundRows)
{
// Get value of Calls here
result = Int32.TryParse(dr["Calls"], out numberOfCalls);
// Optionally, you can check the result of the attempted try parse here
// and do something if you wish
if(result)
{
// Try parse to 32-bit integer worked
}
else
{
// Try parse to 32-bit integer failed
}
}
You can use LINQ to DataSet/DataTable
var rows = dt.AsEnumerable()
.Where(r=> r.Field<int>("ID") == 5);
Since each row has a unique ID, you should use Single/SingleOrDefault which would throw exception if you get multiple records back.
DataRow dr = dt.AsEnumerable()
.SingleOrDefault(r=> r.Field<int>("ID") == 5);
(Substitute int for the type of your ID field)
I could use the following code.
Thanks everyone.
int intID = 5;
DataTable Dt = MyFuctions.GetData();
Dt.PrimaryKey = new DataColumn[] { Dt.Columns["ID"] };
DataRow Drw = Dt.Rows.Find(intID);
if (Drw != null) Dt.Rows.Remove(Drw);
You can try with method select
DataRow[] rows = table.Select("ID = 7");
DataRow dataRow = dataTable.AsEnumerable().FirstOrDefault(r => Convert.ToInt32(r["ID"]) == 5);
if (dataRow != null)
{
// code
}
If it is a typed DataSet:
MyDatasetType.MyDataTableRow dataRow = dataSet.MyDataTable.FirstOrDefault(r => r.ID == 5);
if (dataRow != null)
{
// code
}
try this code
DataRow foundRow = FinalDt.Rows.Find(Value);
but set at lease one primary key
Hello just create a simple function that looks as shown below.. That returns all rows where the call parameter entered is valid or true.
public DataTable SearchRecords(string Col1, DataTable RecordDT_, int KeyWORD)
{
TempTable = RecordDT_;
DataView DV = new DataView(TempTable);
DV.RowFilter = string.Format(string.Format("Convert({0},'System.String')",Col1) + " LIKE '{0}'", KeyWORD);
return DV.ToTable();
}
and simply call it as shown below;
DataTable RowsFound=SearchRecords("IdColumn", OriginalTable,5);
where 5 is the ID.
Thanks..
Try avoiding unnecessary loops and go for this if needed.
string SearchByColumn = "ColumnName=" + value;
DataRow[] hasRows = currentDataTable.Select(SearchByColumn);
if (hasRows.Length == 0)
{
//your logic goes here
}
else
{
//your logic goes here
}
If you want to search by specific ID then there should be a primary key in a table.
By trying to avoid to many foreach()->if() routines, i tried a lambda-concept to search through a bunch of DataTables. I had no errors until i debugged my code to see it does not work, because its not allowed to ask my datarow-column for its index... is there any way to make this work instead of using IndexOf()?
static Entity.Produkt ProduktConstructor(DataRow dr)
{
Entity.Produkt p = new Entity.Produkt();
DataTable dt = Entity.KbMirror.mirror.Tables["Produkt"];
p.id = Guid.Parse(dr[0].ToString());
p.name = dr[1].ToString();
byte[] ba = dt.Rows[dt.IndexOf(dt.Select().Where(r => r[0].ToString() == p.id.ToString()))]["ProduktLogo"];
p.logo = Converter.ImageConverter.BA2Image(ba);
foreach (DataRow pvdr in Entity.KbMirror.mirror.Tables["Produkt_Version"].Rows)
if (Guid.Parse(pvdr[1].ToString()) == p.id)
p.version.Add(VersionConstructor(Guid.Parse(pvdr[2].ToString() ), Guid.Parse(pvdr[0].ToString() ) ) );
return p;
}
static Entity.Version VersionConstructor(Guid vid, Guid pvid)
{
Entity.Version version = new Entity.Version();
DataTable dt = Entity.KbMirror.mirror.Tables["Version"];
version.id = vid;
version.name = dt.Rows[dt.IndexOf(dt.Select().Where(r =>r[0].ToString() == vid.ToString()))][1].ToString();
foreach (DataRow cvdr in Entity.KbMirror.mirror.Tables["Customer_ProduktVersion"].Rows)
if (Guid.Parse(cvdr[2].ToString()) == pvid)
version.customerCollection.Add(CustomerConstructor(Guid.Parse(cvdr[1].ToString())));
return version;
}
EDIT:
error occures when I use "IndexOf()" like this:
byte[] ba = dt.Rows[dt.IndexOf(dt.Select().Where(r => r[0].ToString() == p.id.ToString()))]["ProduktLogo"];
Have you tried passing the entire table as opposed to just the row? Once you pass the entire table, then you can reference just that row of the table.
Also: http://msdn.microsoft.com/en-us/library/bb552415%28v=vs.110%29.aspx
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products = ds.Tables["Product"];
IEnumerable<DataRow> query =
from product in products.AsEnumerable()
select product;
Console.WriteLine("Product Names:");
foreach (DataRow p in query)
{
Console.WriteLine(p.Field<string>("Name"));
}