I have a table with the following fields:
ID | MarketID | CommodityID | CurrencyID | PriceValue | Year | Month
With the following data:
1 | 100 | 30 | 15 | 3.465 | 2018 | 03
2 | 100 | 30 | 15 | 2.372 | 2018 | 04
3 | 100 | 32 | 15 | 1.431 | 2018 | 02
4 | 100 | 32 | 15 | 1.855 | 2018 | 03
5 | 100 | 32 | 15 | 2.065 | 2018 | 04
6 | 101 | 30 | 15 | 7.732 | 2018 | 03
7 | 101 | 30 | 15 | 8.978 | 2018 | 04
8 | 101 | 32 | 15 | 4.601 | 2018 | 02
9 | 101 | 32 | 18 | 0.138 | 2017 | 12
10 | 101 | 32 | 18 | 0.165 | 2018 | 03
11 | 101 | 32 | 18 | 0.202 | 2018 | 04
As you can see the date is (unfortunately) saved as an integer in the Year and Month fields.
I want to get from the above data, using LINQ to Entities (EF6), the latest PriceValue for each Market-Commodity-Currency record.
So the expected result should be:
2 | 100 | 30 | 15 | 2.372 | 2018 | 04
5 | 100 | 32 | 15 | 2.065 | 2018 | 04
7 | 101 | 30 | 15 | 8.978 | 2018 | 04
8 | 101 | 32 | 15 | 4.601 | 2018 | 02
11 | 101 | 32 | 18 | 0.202 | 2018 | 04
I've tried with the following queries but none of them can give me the expected results:
var lastValues = (from a in Analysis
group a by a.ID into g
select g.OrderByDescending(t => ((t.Year* 100) + t.Month)));
and the following that has more sense of the previous one, but I loose the PriceValue field:
var lastValues = (from a in Analysis
group a by new {a.MarketID, a.CommodityID, a.CurrencyID } into g
select new
{
g.Key.MarketID,
g.Key.CommodityID,
g.Key.CurrencyID,
date = g.Max(t => ((t.Year* 100) + t.Month))
});
Is there a way to have a single LINQ query to get only the records with the latest date as I've described above?
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication45
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("MARKETID", typeof(int));
dt.Columns.Add("CommodityID", typeof(int));
dt.Columns.Add("CurrencyID", typeof(int));
dt.Columns.Add("PriceValue", typeof(decimal));
dt.Columns.Add("Year", typeof(int));
dt.Columns.Add("Month", typeof(int));
//ID | MarketID | CommodityID | CurrencyID | PriceValue | Year | Month
dt.Rows.Add(new object[] {1 , 100 , 30 , 15 , 3.465 , 2018 , 03});
dt.Rows.Add(new object[] {2 , 100 , 30 , 15 , 2.372 , 2018 , 04});
dt.Rows.Add(new object[] {3 , 100 , 32 , 15 , 1.431 , 2018 , 02});
dt.Rows.Add(new object[] {4 , 100 , 32 , 15 , 1.855 , 2018 , 03});
dt.Rows.Add(new object[] {5 , 100 , 32 , 15 , 2.065 , 2018 , 04});
dt.Rows.Add(new object[] {6 , 101 , 30 , 15 , 7.732 , 2018 , 03});
dt.Rows.Add(new object[] {7 , 101 , 30 , 15 , 8.978 , 2018 , 04});
dt.Rows.Add(new object[] {8 , 101 , 32 , 15 , 4.601 , 2018 , 02});
dt.Rows.Add(new object[] {9 , 101 , 32 , 18 , 0.138 , 2017 , 12});
dt.Rows.Add(new object[] {10 , 101 , 32 , 18 , 0.165 , 2018 , 03});
dt.Rows.Add(new object[] { 11, 101, 32, 18, 0.202, 2018, 04 });
List<DataRow> results = dt.AsEnumerable()
.OrderByDescending(x => new DateTime(x.Field<int>("Year"), x.Field<int>("Month"), 1))
.GroupBy(x => new { market = x.Field<int>("MarketID"), commodity = x.Field<int>("CommodityID"), currency = x.Field<int>("CurrencyID") })
.Select(x => x.First())
.ToList();
}
}
}
I've finally found the way to include also the PriceValue in the results.
Starting from the last query I've posted, I've to simply add the
g.OrderByDescending(t => ((t.Year* 100) + t.Month)).FirstOrDefault().PriceValue
So it will be:
var lastValues = (from a in Analysis
group a by new {a.MarketID, a.CommodityID, a.CurrencyID } into g
select new
{
g.Key.MarketID,
g.Key.CommodityID,
g.Key.CurrencyID,
date = g.Max(t => ((t.Year* 100) + t.Month)),
g.OrderByDescending(t => ((t.Year* 100) + t.Month)).FirstOrDefault().PriceValue
});
I prefer this solution as it's based on the current query I've developed.
Try This Linq Query
var lastValues = (from ak in Analysis
group ak by new { ak.MarketID, ak.CommodityID, ak.CurrencyID } into g
select new
{
g.Key.MarketID,
g.Key.CommodityID,
g.Key.CurrencyID,
pricevalue = g.OrderByDescending(c=>c.Year).ThenByDescending(c=>c.Month).FirstOrDefault().PriceValue,
year = g.OrderByDescending(c => c.Year).ThenByDescending(c => c.Month).FirstOrDefault().Year,
month = g.OrderByDescending(c => c.Year).ThenByDescending(c => c.Month).FirstOrDefault().Month
});
Using Orderby and ThenBy
i have two tables suck as the one below i wanna know how to sum "calorie" column based on name from table 1 and then insert the value to table 2
table1(PK->ID(int),Name(nvarchar),amount(int),calorie(int))
table2(pk->ID(int),name(nvarchar),totalcalorie(int))
+-------+--------+----------+--------------+
| int | name | amount | calorie |
+-------+--------+----------+--------------+
| 1 | a | 10 | 20 |
| 2 | b | 5 | 20 |
| 2 | b | 10 | 10 |
| 1 | a | 10 | 10 |
| 2 | b | 15 | 35 |
| 3 | c | 20 | 15 |
+-------+--------+----------+--------------+
something like this is my first table now imagine same kinda table for table2
only this time something like :
1-------a--------30
2-------b--------65
3-------c--------15
is this possible at all? what i wrote till now and doesn't work is this :
DataClasses1DataContext db = new DataClasses1DataContext();
var q = from row in db.table1
group row by new { row.name }
into grp
select new
{
grp.Key.name,
sum = grp.Sum(row => row.calorie)
};
db.SubmitChanges();
Now you are just selecting data. You need the block for insertion like the following:
var q = (from row in db.table1
group row by new { row.id, row.name } into grp
select new
{
grp.Key.id,
grp.Key.name,
sum = grp.Sum(s => s.calorie)
}).ToList();
foreach(var item in q)
{
var e = new db.table2Entity
{
id = item.id,
name = item.name,
totalcalorie = item.sum
};
db.Table2.AddObject(e);
}
db.SaveChanges();
I think that you do not see the result on you databse after db.SubmitChanges() wright ? Linq query should work fine but Submit doesn't see the change becouse there is no change in table2. You only select data and group it from table1. Please debug and see what is in q variable.
I have a datatable. it has 5 columns say (Type, A1, A2, B1, B2)
If Type is A, I want to make sure no 2 rows will have same data in A1 and A2 columns and
for Type B, no 2 rows will have same data in B1 and B2 columns
e.g.
Type | A1 | A2 | B1 | B2 |
--------------------------
1 A | 123 | XY | | |
2 A | 123 | XY | | |
3 B | | | TT | LL |
4 A | 456 | YZ | | |
5 B | | | TT | LL |
6 A | 123 | YZ | | |
7 B | | | TT | LL |
8 A | 456 | YZ | | |
In this case I want to flag an error on rows 1,2,4,8
and another error on rows 3,5,7.
Row 6 is OK.
To start with I have done Group by on Key= Type as:
var groups = dt.AsEnumerable().GroupBy(r => r["Type"]).ToList();
I am not sure if I further use for-each on each group or is there a better way in linq.
Please guide.
Thanks.
You can use an anonymous type for the GroupBy:
var dupGroups = table.AsEnumerable()
.Select(r => new{
Row = r,
IsA = r.Field<string>("Type")=="A",
IsB = r.Field<string>("Type")=="B",
A1 = r.Field<string>("A1"),
A2 = r.Field<string>("A2"),
B1 = r.Field<string>("B1"),
B2 = r.Field<string>("B2"),
})
.GroupBy(x => x.IsA ? new { Val1 = x.A1, Val2 = x.A2 } : new { Val1 = x.B1, Val2 = x.B2 })
.Where(g => g.Count() > 1);
foreach (var dupGroup in dupGroups)
foreach (DataRow row in dupGroup.Select(x => x.Row))
row.RowError = "Duplicate detected";
Result:
DataTable errors = table.GetErrors().CopyToDataTable();
1 A 123 XY
2 A 123 XY
3 B TT LL
4 A 456 YZ
5 B TT LL
7 B TT LL
8 A 456 YZ
As you can see, row 6 is not part of the error-table because it's not a duplicate.
I've been trying to find a way to create Row Headers (DataGridView) from Tables.
My Table consists name of days e.g. Mon, Tue, Wed, ... so on.
How can I achieve this?
Sorry, I'm very new to C# and I need a huge help.
Here's my code:
string queryString2 = "select * from DayType";
using (SqlCommand command = conn.CreateCommand())
{
command.CommandText = queryString2;
conn.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;
dataGridView1.Rows[0].HeaderCell.Value = (reader["WhichDay"].ToString());
}
}
conn.Close();
//UPDATE:
//This is what i'm trying to achieve:
//-------------------------------------------
// | 12:00 | 13:00 | 14:00 | 15:00 ---> Read from SQL Table 2
//-------------------------------------------
// Mon | 0 | 0 | 0 | 0
//-------------------------------------------
// Tue | 0 | 0 | 0 | 0
//-------------------------------------------
// Wed | 0 | 0 | 0 | 0
//-------------------------------------------
// Thu | 0 | 0 | 0 | 0
//-------------------------------------------
// |
// V
//Read from SQL Table 1
use the below code
dataGridView1.HeaderRow.Cells[0].Text = (reader["WhichDay"].ToString());
I have two Datatables shown in below
Table 1
-------------------------
ID | Name
--------------------------
1 | JOHN
2 | GEORGE
3 | RAGU
--------------------------
Table 2
----------
ID | AGE
----------
1 | 23
2 | 23
3 | 22
----------
I just want the result as like this..
Result
-------------------------
ID | Name | AGE
--------------------------
1 | JOHN | 23
2 | GEORGE | 23
3 | RAGU | 22
--------------------------
Thanks..
you can check this out:
static void Main(string[] args)
{
Program p = new Program();
DataTable dt1= p.Get1();
DataTable dt2 = p.Get2();
DataTable dt3 = p.Get3(dt1, dt2);
}
public DataTable Get1()
{
DataTable dt1 = new DataTable();
dt1.Columns.Add("ID");
dt1.Columns.Add("Name");
dt1.Rows.Add("1", "JOHN");
dt1.Rows.Add("2", "GEORGE");
dt1.Rows.Add("3", "RAGU");
return dt1;
}
public DataTable Get2()
{
DataTable dt2 = new DataTable();
dt2.Columns.Add("AGE");
dt2.Rows.Add("23");
dt2.Rows.Add("23");
dt2.Rows.Add("22");
return dt2;
}
public DataTable Get3(DataTable dt1,DataTable dt2)
{
dt1.Columns.Add("Age");
for (int i = 0; i < dt1.Rows.Count; i++)
{
dt1.Rows[i]["Age"] = dt2.Rows[i]["Age"];
}
return dt1;
}
I assume that this is what you might be looking for
INSERT INTO Result (ID, Name, Age)
SELECT T1.ID, T1.Name, T2.Age
FROM
Table1 AS T1
INNER JOIN
Table2 AS T2
ON
T1.ID = T2.ID
ORDER BY
T1.ID
Have you heard about INNER JOIN?
Basically, what you want to do is:
SELECT Persons.ID, Persons.Name, Ages.Age
FROM Persons INNER JOIN Ages ON Persons.ID = Ages.ID
Now you can insert that into another table if you want.