How to get all unique records with the maximum value in column using LINQ - linq

Learner | AssesmentId | Attempt
------------------------------------
Parker | 1 | 1
Parker | 1 | 2
Stark | 1 | 1
Rogers | 1 | 1
Rogers | 1 | 2
Parker | 1 | 3
Given this data, how do I get all the unique Student name with the highest Attempt?
I'm attempting to get this result:
Learner | AssesmentId | Attempt
------------------------------------
Parker | 1 | 3
Stark | 1 | 1
Rogers | 1 | 2
How can I do this in a single query in LINQ?
from la in _context.LearnerAssessments
where la.AssessmentId == assessmentId
&& learnerIds.Contains(la.LearnerId)
&& la.Attempt == {highest attempt}

var data = from list in _context.LearnerAssessments
group list by new
{
list.Learner,
list.AssesmentId
}
into g
select new
{
g.Key.Learner,
g.Key.AssesmentId,
Max= g.Max(x=>x.Attempt)
};
or using fluent API :
var data = _context.LearnerAssessments.GroupBy(l => new { l.Learner, l.AssesmentId }, (keys, item) => new
{
Key = keys,
MaxAttemp = item.Max(x => x.Attempt)
}).Select(x => new LearnerAssessment
{
Learner = x.Key.Learner,
Attempt = x.MaxAttemp,
AssesmentId = x.Key.AssesmentId
});

Related

Yii2 AR left join with where and relations

Book
----------------------------
| id | name | published |
----------------------------
| 1 | book1 | 1 |
| 2 | book2 | 1 |
| 3 | book3 | 0 |
Chapter
----------------------------
| id | book_id | name | published |
----------------------------
| 1 | 1 | chapter1 | 1 |
| 2 | 1 | chapter2 | 0 |
| 2 | 2 | chapter1 | 0 |
| 3 | 3 | chapter1 | 1 |
class Book{
public function getChapter()
{
return $this->hasMany(Chapter::className(), ['kook_id' => 'id']);
} }
class Chapter{
public function getBook()
{
return $this->hasOne(Book::className(), ['id' => 'book_id']);
} }
How can i get published books with published pages using ActiveRecord (i want get book1 with chapter1 and book2 without any chapters)?
smth like Book::find($id)->where(['published' => 1])-> {{{left join with where}}} ->all())
ADDED
And then i wand to use it
echo $book->name;
foreach($book->getChapter() as chapter){
echo chapter->name;
}
Change your Book class relation as
class Book
{
public function getChapter()
{
return $this->hasMany(Chapter::className(), ['book_id' => 'id'])->where(['published' => 1]);
}
}
To get Related Records use with()
Book::find()->with(['chapter'])->where(['id' => $id ,'published' => 1])->all()
To Use it:
//Book Name
echo $book->name;
//For Chapters Name
if($book->chapter){
foreach($book->chapter as $chapter){
echo $chapter->name;
}
}

Multiple Tables Group and substract sum of columns using linq sql

Here i have two tables
Table One
+---------------+----------+------------+
| Raw Material | Size | Qty |
+---------------+----------+------------+
| A | 1 | 5 |
| A | 2 | 2 |
| A | 1 | 2 |
| B | 0 | 5 |
| B | 0 | 1 |
+---------------+----------+------------+
Table Two
+---------------+----------+------------+
| Raw Material | Size | Qty |
+---------------+----------+------------+
| A | 1 | 2 |
| A | 2 | 1 |
| A | 1 | 1 |
+---------------+----------+------------+
I want out put like
+---------------+----------+------------+
| Raw Material | Size | Qty |
+---------------+----------+------------+
| A | 1 | 4 |
| A | 2 | 1 |
| B | 0 | 6 |
+---------------+----------+------------+
Want to get substract first two tables sum of qty by grouping Rawmaterial and Size
Something like this should do the job
var result = tableA.Select(e => new { Item = e, Factor = 1 })
.Concat(tableB.Select(e => new { Item = e, Factor = -1 }))
.GroupBy(e => new { e.Item.RawMaterial, e.Item.Size }, (key, elements) => new
{
RawMaterial = key.RawMaterial,
Size = key.Size,
Qty = elements.Sum(e => e.Item.Qty * e.Factor)
}).ToList();
First we create a union of the two tables using Concat, including the information which one is additive (in Factor field), and then just do the normal grouping.
If you want the result to be List<YourTableElementType>, just replace the final anonymous type projection (new { ... }) with new YourTableElementType { ... }.

LINQ - How to select with subquery

My data is:
+-----+--------+-----------+
| Id | Name | ParentId |
+-----+--------+-----------+
| 1 | A | 0 |
| 2 | B | 0 |
| 3 | C | 1 |
+-----+--------+-----------+
How do I get C if we have ParentId = 0 by LINQ?
Assuming "Categories" is the collection name, I think this is what you need.
var parentCategoryIds = Collections.Where(c => c.ParentId == 0).Select(c => c.Id);
var results = Collections.Where(c => parentCategoryIds.Contains(c.ParentId));
And if you want to get the name, you can do
var names = results.Select(r => r.Name);
These three statements could be written into one linq statement but I did this for clarity.

Best Practice for retrieving and iterating over one to many

I'm trying to produce a web page report of Orders Per Customer with line item details for each order.
So it looks like this:
Customer 1 | Order 1 | Item 1 |
| | == New Row == |
| | Item 2 |
| | == New Row == |
| | Item 3 |
| | == New Row == |
| ====== New Row ========= |
| Order 2 | Item 1 |
| | == New Row == |
| | Item 2 |
| | == New Row == |
| | Item 3 |
| | == New Row == |
| ====== New Row ========= |
| Order 3 | Item 1 |
| | Item 2 |
== New Row ==============================
Customer 2 | Order 1 | Item 1 |
| | == New Row == |
| | Item 2 |
| | == New Row == |
| | Item 3 |
| | == New Row == |
| | Item 4 |
| | == New Row == |
| | Item 5 |
| | == New Row == |
| ====== New Row ========= |
| Order 2 | Item 1 |
| | == New Row == |
| | Item 2 |
| | == New Row == |
| | Item 3 |
== New Row ==============================
Is it better to get an array list of data as follows:
1 | 1 | 1 |
1 | 1 | 2 |
1 | 1 | 3 |
1 | 2 | 1 |
1 | 2 | 2 |
1 | 2 | 3 |
1 | 3 | 1 |
1 | 3 | 2 |
2 | 1 | 1 |
2 | 1 | 2 |
2 | 1 | 3 |
2 | 1 | 4 |
2 | 1 | 5 |
2 | 2 | 1 |
2 | 2 | 2 |
2 | 2 | 3 |
and pass 1 JavaBean and use JSTL to determine the nesting as follows:
this is incomplete for brevity
<table><tr><th>Customer No</th><th>Orders</th></tr>
<c:forEach var="custOrderLineItem" items="${customerOrderLineItemList}">
<c:set var="currentOrder" value="custOrderLineItem.orderId">
<c:set var="currentCustomer" value="custOrderLineItem.customerId">
<c:if test="${currentOrder != custOrderLineItem.orderId}">
==New Row==
</c:if>
or is it better to use nested JavaBeans
Customer.setOrders<List>
Orders.setOrderDetails<List>
OrderDetails.setLineItem<List>
and then use JSTL as such
<c:forEach var="customer" items="${customerList}">
<c:forEach var="order" items="${customer.orderList}">
<c:forEach var="lineItem" items="${order.detailList}">
After spending the time writing this, I feel like the second method looks cleaner and easier. But the first method seems to have an easier SQL query. I'm not using JPA, just basic JDBC sql calls. So how does one populate nested JavaBeans, without JPA? Do you do something like this?
List<Customer> custList = getCustomerList();
ListIterator custListIter = custList.listIterator();
while (custListIter.hasNext()) {
customer = (Customer) custListIter.next();
List<Order> orderList = getOrderList(customer.getId());
ListIterator orderListIter = orderList.listIterator();
while (orderListIter.hasNext()) {
order = (Order) orderListIter.next();
List orderDetailsList<OrderDetail> = getOrderDetailList(order.getId);
order.setOrderDetails(orderDetailsList);
orderListIter.set(order);
}
customer.setOrderList(orderList);
custListIter.set(customer);
}
You could simply make the SQL query which returns everything, and build the graph of objects from the result set. Using maps to keep an association between IDs and the corresponding objects:
Map<Long, Customer> customersById = new HashMap<Long, Customer>();
Map<Long, Order> ordersById = new HashMap<Long, Order>();
Map<Long, Item> itemsById = new HashMap<Long, Item>();
while (rs.next()) {
Long customerId = rs.getLong(1);
Customer customer = customersById.get(customerId);
if (customer == null) {
customer = new Customer(customerId);
// populate other fields of customer
customersById.put(customerId, customer);
}
Long orderId = rs.getLong(5);
Order order = ordersById.get(orderId);
if (order == null) {
order = new Order(orderId);
customer.addOrder(order);
// populate other fields of order
ordersById.put(orderId, order);
}
// same for items
}
At the end of the loop, you have all the customers, each with their orders, each with their items.

Codeigniter Datamapper save as new id

I'm new to datamapper. I have a problem on trying to duplicate a result into a new id.
This is a simplified table for my database:
Job Table
| id | property_id | name | type |
| 1 | 1 | abc | i |
| 2 | 2 | def | ii |
Property Table
| id | job_id | size |
| 1 | 1 | 90 |
| 2 | 2 | 40 |
How can I automatically duplicate a new job based on job id 1 into new job/property id like
Job Table
| id | property_id | name | type |
| 1 | 1 | abc | i |
| 2 | 2 | def | ii |
| 3 | 3 | abc | i |
Property Table
| id | job_id | size |
| 1 | 1 | 90 |
| 2 | 2 | 40 |
| 3 | 3 | 90 |
Thanks for helping! :)
In the documentation for DataMapper Overzealous Edition: http://datamapper.wanwizard.eu/pages/clonecopy.html There's clone and copy, copy will clear the id. Here's their example, just skip the part of making changes:
// Let's save a new hosting plan
$p = new Plan();
$p->name = 'The 100GB Plan';
$p->storage = 1000;
$p->bandwidth = 2000;
$p->databases = 5;
$p->domains = 5;
$p->emails = 50;
$p->save();
// Now, lets make a copy of that saved plan and base a new one off of it
$p = $p->get_copy();
// Change only what we need to
$p->name = 'The Big 150GB Plan';
$p->storage = 1500;
$p->bandwidth = 2500;
// And now save a new record
$p->save();
You can also just modify the object you retrieve, and then use save_as_new() to save it as a new record.

Resources