Fill in the table values in the foreign key - c#

I have two tables Table1 and Table2, each with two columns: Id, Name.
Tables are filled with some data. I want to create a new table with the columns: Id, T1_Id, T2_Id, where T1_Id and T2_Id are foreign keys to Table1 and Table2 respectively.
How to create the table as quickly as possible to fill it with all the values and T1_Id, T2_Id already contained in the tables Table1 and Table2?
For example:
Table 1:
Id Name
1 T1N1
2 T1N2
3 T1N3
Table 2:
Id Name
1 T2N1
2 T2N2
Result table;
Id T1_Id T2_Id
1 1 1
2 2 1
3 3 1
4 1 2
5 2 2
6 3 2

Use CROSS JOIN to get the Cartesian product of Table 1 and Table 3.
Try this
select row_number() over(order by T2_Id,T1_Id) as Id,
T1_Id ,
T2_Id
From [Table 1] A
CROSS JOIN [Table 3] B

You would use cross join:
select row_number() over (order by (select null)) as id,
t1.id as t1_id, t2.id as t2_id
into result
from table1 t1 cross join table2 t2;
This assumes that you don't actually care about the ordering of the id column in the result table. If you do, you can do:
select row_number() over (order by t1.id, t2.id) as id,
t1.id as t1_id, t2.id as t2_id
into result
from table1 t1 cross join table2 t2;
The first version is faster, because the second will actually do a sort.

Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable dt1 = new DataTable();
dt1.Columns.Add("Id", typeof(int));
dt1.Columns.Add("Name", typeof(string));
dt1.Rows.Add(new object[] {1, "T1N1"});
dt1.Rows.Add(new object[] {2, "T1N2"});
dt1.Rows.Add(new object[] {3, "T1N3"});
DataTable dt3 = new DataTable();
dt3.Columns.Add("Id", typeof(int));
dt3.Columns.Add("Name", typeof(string));
dt3.Rows.Add(new object[] {1, "T2N1"});
dt3.Rows.Add(new object[] {2, "T2N2"});
DataTable results = new DataTable();
results.Columns.Add("Id", typeof(int));
results.Columns.Add("T1_Id", typeof(int));
results.Columns.Add("T2_Id", typeof(int));
int id = 1;
foreach (DataRow row3 in dt3.AsEnumerable())
{
foreach (DataRow row1 in dt1.AsEnumerable())
{
results.Rows.Add(new object[] { id++, row3.Field<int>("Id"), row1.Field<int>("Id") });
}
}
}
}
}

Related

How to throuhly join two datatables using linq without column names

This is propably answered somewhere else, but I haven't found working solution yet.
I have two datatables and I want to join them into one datatable containing all data from both of them, or at least from the first of them and some columns from the second datatable.
I don't want to list all columns (totally 180) from the first datatable. I have tried eg. this
var JoinedResult = from t1 in table1.Rows.Cast<DataRow>()
join t2 in table2.Rows.Cast<DataRow>()
on Convert.ToInt32(t1.Field<string>("ProductID")) equals t2.Field<int>("FuelId")
select t1;
but that gives only the columns from table1. How to get colums from table2 too to my result? Finally, I need to add my result to a dataset.
ResultSet.Tables.Add(JoinedResult.CopyToDataTable());
EDIT:
I ended up with this as the solution.
This follows an example given here Create join with Select All (select *) in linq to datasets
DataTable dtProduct = dsProduct.Tables[0];
DataTable dtMoistureLimits = ds.Tables[0];
//clone dt1, copies all the columns to newTable
DataTable dtProductWithMoistureLimits = dtProduct.Clone();
//copies all the columns from dt2 to newTable
foreach (DataColumn c in dtMoistureLimits.Columns)
dtProductWithMoistureLimits.Columns.Add(c.ColumnName, c.DataType);
var ProductsJoinedWithMoistureLimits = dtProduct.Rows.Cast<DataRow>()
.Join(dtMoistureLimits.Rows.Cast<DataRow>(),// join table1 and table2
t1 => new { ProductID = t1.Field<int>("ProductID"), DelivererID = t1.Field<int>("DelivererID") },
t2 => new { ProductID = t2.Field<int>("MoistureLimits_ProductID"), DelivererID = t2.Field<int>("MoistureLimits_DelivererID") },
(t1, t2) => // when they match
{ // make a new object
// containing the matching t1 and t2
DataRow row = dtProductWithMoistureLimits.NewRow();
row.ItemArray = t1.ItemArray.Concat(t2.ItemArray).ToArray();
dtProductWithMoistureLimits.Rows.Add(row);
return row;
});
However, in dtMoistureLimits there is not rows for all "ProductID" and "DelivererID" in dtProduct. Currently my solution returns only matching rows.
How to improve solution to return also those rows where there is not data for "ProductID" and "DelivererID" in dtMoistureLimits?
Solution using method syntax, without having to mention all columns
var result = table1.Rows.Cast<DataRow>()
.Join(table2.Rows.Cast<DataRow>(), // join table1 and table2
t1 => Convert.ToInt32(t1.Field<string>("ProductID")) // from every t1 get the productId
t2 => t2.Field<int>("FuelId") // from every t2 get the fuelId,
(t1, t2) => new // when they match
{ // make a new object
T1 = t1, // containing the matching t1 and t2
T2 = t2,
}
var JoinedResult = (from t1 in table1.Rows.Cast<DataRow>()
join t2 in table2.Rows.Cast<DataRow>()
on Convert.ToInt32(t1.Field<string>("ProductID")) equals t2.Field<int>("FuelId")
select new { T1 = t1,
T2 = t2.column_name // all columns needed can be listed here
}).ToList();
EDIT:
To convert the above result to a DataTable, use the following method:
DataTable dataTable = new DataTable();
//Get all the properties
PropertyInfo[] Props = JoinedResult.Select(y=>y.T1).First().GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
//Defining type of data column gives proper data table
var type = (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) ? Nullable.GetUnderlyingType(prop.PropertyType) : prop.PropertyType);
//Setting column names as Property names
dataTable.Columns.Add(prop.Name, type);
}
dataTable.Columns.Add(t2_column_name, t2_column_type);
foreach (var item in JoinedResult)
{
var values = new object[Props.Length];
for (int i = 0; i < Props.Length; i++)
{
//inserting property values to datatable rows
values[i] = Props[i].GetValue(item.T1, null);
}
values[Props.Length] = item.T2;
dataTable.Rows.Add(values);
}

Building linq query that collect records by group

scenario is simple actually but handling it in linq require more exp than I have..
There is 3 table
Table1
ID Column
1 val1
2 val2
Table2
ID Column
1 val3
2 val4
Table3
ID Column
1 val5
2 val6
I need such a query that returns;
TableResult:
Row ID Column Type
1 1 val1 table1
2 2 val2 table1
3 1 val3 table2
4 2 val4 table2
5 1 val5 table3
6 2 val6 table3
Searched on net and started like below but cant figure how handle the tricks create "type", merge records etc..
from t1 in table1
join t2 in table2 on t1.id equals t2.id
join t3 in table3 on t1.id equals t3.id
select new {...}
You've already accepted an answer, so I don't know if this is what you WANT, but it generates the output you specified in your post.
Because you have only used Id values of 1 and 2, it's unclear whether you actually want to perform a Join or just get the set of all rows into a single result.
Anyway:
struct TableStructure
{
public int Id { get; set; }
public string Column { get; set; }
}
var t1 = new List<TableStructure>() { new TableStructure { Id = 1, Column = "val1" }, new TableStructure { Id = 2, Column = "val2" } };
var t2 = new List<TableStructure>() { new TableStructure { Id = 1, Column = "val3" }, new TableStructure { Id = 2, Column = "val4" } };
var t3 = new List<TableStructure>() { new TableStructure { Id = 1, Column = "val5" }, new TableStructure { Id = 2, Column = "val6" } };
var result = ((from row1 in t1 select new { row1.Id, row1.Column, SourceTable = "table1" })
.Union(from row2 in t2 select new { row2.Id, row2.Column, SourceTable = "table2" })
.Union(from row3 in t3 select new { row3.Id, row3.Column, SourceTable = "table3" }))
.AsEnumerable().Select((row, index) => new { RowNum = index + 1, row.Id, row.Column, row.SourceTable });
result.ToList().ForEach(row => Console.WriteLine($"{row.RowNum}, {row.Id}, {row.Column}, {row.SourceTable}"));
output:
1, 1, val1, table1
2, 2, val2, table1
3, 1, val3, table2
4, 2, val4, table2
5, 1, val5, table3
6, 2, val6, table3
Same as what you did try Distinct at the end. query syntax would be :
var List = (from t1 in dbContext.table1
join t2 in dbContext.table2 on t1.ID equals t2.ID
join t3 in dbContext.table3 on t1.ID equals t3.ID
select new
{
//t1.DesiredColumnName,
//t2.DesiredColumnName,
//t3.DesiredColumnName,
//so on
}).Distinct().ToList();

SQL display table in vertical

I am using C# and MySQL as (DBMS) I want to rotate my table. this is my query :
SELECT p.gender,Count(CASE WHEN disease like '%Anemia%' THEN 1 END) AS 'Anemia'
,Count(CASE WHEN disease like '%Injuries%' THEN 1 END) AS 'Injuries'
FROM phc_db.record r, phc_db.patient p
where r.malteser_id=p.malteser_id
group by p.gender
The result is :
Gender Anemia Injuries
------------------------
Female 1 0
Male 2 1
------------------------
And I want :
Disease Male Female
----------------------
Anemia 2 1
Injuries 1 0
----------------------
Any Idea? Any Suggestion?
Thanks
You can try pivoting on the disease instead of the gender. In this case, the genders become columns.
SELECT
disease,
SUM(CASE WHEN p.gender = 'Male' THEN 1 END) AS Male,
SUM(CASE WHEN p.gender = 'Female' THEN 1 END) AS Female
FROM phc_db.record r
INNER JOIN phc_db.patient p
ON r.malteser_id = p.malteser_id
GROUP BY disease
WHERE disease IN ('Anemia', 'Injuries')
Note that from your current output it appears that you may not need to use LIKE to match diseases. In my query above, I check for the exact disease names of anemia and injuries. If I assumed wrongly, then you can bring back LIKE.
Swap the aggregation:
SELECT
(CASE WHEN disease LIKE '%Anemia%' THEN 'Anemia'
WHEN disease like '%Injuries%' THEN 'Injury'
END) AS disease,
SUM (p.gender = 'Female') AS females,
SUM (p.gender = 'Male') AS males
FROM phc_db.record r
INNER JOIN phc_db.patient p
ON r.malteser_id = p.malteser_id
WHERE disease REGEXP 'Anemia|Injuries'
GROUP BY disease;
You can do in c# with following query which will get all the diseases
SELECT p.gender, disease
FROM phc_db.record r, phc_db.patient p
where r.malteser_id=p.malteser_id
The use following c#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("Gender", typeof(string));
dt.Columns.Add("Disease", typeof(string));
dt.Rows.Add(new object[] { "Male", "Anemia"});
dt.Rows.Add(new object[] { "Female", "Anemia"});
dt.Rows.Add(new object[] { "Male", "Anemia"});
dt.Rows.Add(new object[] { "Female", "Anemia"});
dt.Rows.Add(new object[] { "Male", "Anemia"});
dt.Rows.Add(new object[] { "Male","Injuries" });
dt.Rows.Add(new object[] { "Female", "Injuries" });
dt.Rows.Add(new object[] { "Male", "Injuries" });
dt.Rows.Add(new object[] { "Female", "Injuries" });
string[] uniqueDieses = dt.AsEnumerable().Select(x => x.Field<string>("Disease")).Distinct().ToArray();
DataTable pivot = new DataTable();
pivot.Columns.Add("Disease", typeof(string));
pivot.Columns.Add("Male", typeof(int));
pivot.Columns.Add("Female", typeof(int));
var groups = dt.AsEnumerable()
.GroupBy(x => x.Field<string>("Disease")).Select(x => new
{
disease = x.Key,
male = x.Where(y => y.Field<string>("Gender") == "Male").Count(),
female = x.Where(y => y.Field<string>("Gender") == "Female").Count()
}).ToList();
foreach (var group in groups)
{
pivot.Rows.Add(new object[] { group.disease, group.male, group.female });
}
}
}
}

Sqlite Get sum Columns based on another column

I have a SQLite table data like this given below.
ID Type Amount
-----------------------
1 A 10
1 B 5
2 A 4
2 B 7
3 A 2
3 B 8
What i wanted to present in a datagridview is something like this
ID A B
-------------
1 10 5
2 4 7
3 2 8
This is in SQLite database. I need to show the data in datagridview. Currently i am taking the first dataset and using code to loop through to get the desired result but the table has a lot of results and therefore the process is extremely slow.
Can you guys please tell me how can i get the second result directly. I have search but i could not find any appropriate sql query to get this result
You can do that with a conditional aggregation
select ID,
sum(case when Type = 'A' then Amount) as A
sum(case when Type = 'B' then Amount) as B
from yourTable
group by ID
Another option is to join the table with itself
select ID, t1.Amount as A, t2.Amount as B
from yourTable t1
join yourTable t2
on t1.ID = t2.ID
where t1.Type = 'A' and
t2.Type = 'B'
The first option requires you to have only one row per ID / Type, but if that's the case performs better. The second one is safer, but joining the table with itself will decrease its performances
This should do:
SELECT ID,
SUM(CASE WHEN Type = 'A' THEN Amount ELSE 0 END) as A,
SUM(CASE WHEN Type = 'B' THEN Amount ELSE 0 END) as B
FROM TABLE
GROUP BY ID
You want a pivot table :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication49
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Type", typeof(string));
dt.Columns.Add("Amount", typeof(int));
dt.Rows.Add(new object[] {1, "A", 10});
dt.Rows.Add(new object[] {1, "B", 5});
dt.Rows.Add(new object[] {2, "A", 14});
dt.Rows.Add(new object[] {2, "B", 7});
dt.Rows.Add(new object[] {3, "A", 2});
dt.Rows.Add(new object[] {3, "B", 8});
string[] uniqueTypes = dt.AsEnumerable().Select(x => x.Field<string>("Type")).Distinct().ToArray();
DataTable pivot = new DataTable();
pivot.Columns.Add("ID", typeof(int));
foreach (string _type in uniqueTypes)
{
pivot.Columns.Add(_type, typeof(int));
}
var groups = dt.AsEnumerable().GroupBy(x => x.Field<int>("ID")).ToList();
foreach (var group in groups)
{
DataRow newRow = pivot.Rows.Add();
newRow["ID"] = group.Key;
foreach (DataRow row in group)
{
newRow[row.Field<string>("Type")] = row.Field<int>("Amount");
}
}
}
}
}

SELECT all columns in addition to some summary columns using LINQ

Suppose there is a table with more than 20 columns: (col1, col2, ... )
If I want to display the sum of col1 and col2 as well as the other columns,
In SQL I could:
SELECT (col1+col2), * FROM table1;
But in LINQ, I have to
from tb in table1
select new
{
sum = tb.col1 + tb.col2,
col1 = tb.col1,
col2 = tb.col2,
...
};
Is there another simpler ways? Thanks.
You can extend type of tb entity by sum property and write something like:
table1
.Select(tb => new
{
Tb = tb,
Sum = tb.col1 + tb.col2
})
.Select(x =>
{
x.Tb.sum = x.Sum;
return x.Tb;
});

Categories