How can I create a virtual summation field by entity - mysql

I have records which have a sq. mileage field. I want to sum these fields by date, so regardless of display page, order, etc. the value by entity will be the same.
e.g.:
|id| date |sqmiles|total|
|--|----------|-------|-----|
|1 |2010-10-10| 2 | 2 |
|2 |2011-11-11| 3 | 5 |
|3 |2012-12-12| 1 | 6 |
|id| date |sqmiles|total|
|--|----------|-------|-----|
|3 |2012-12-12| 1 | 6 |
|1 |2010-10-10| 2 | 2 |
|2 |2011-11-11| 3 | 5 |
My starting thoughts were a virtual field where it requests the following SQL:
SELECT SUM(sq_miles) FROM table WHERE date <= ($this->_properties['date']); but with CakePHP3's new ORM I don't know how to put that into code.

This may not be the "best" answer, but I made it work:
In the entity add use Cake\ORM\TableRegistry; then the following function:
protected function _getTotalSqMiles()
{
$annexations = TableRegistry::get('Annexations');
$query = $annexations->find();
$sum = $query->func()->sum('sq_miles');
$results = $query->select(['total' => $sum])
->where([
'effective_date <=' => $this->_properties['effective_date']
])
->first();
return $results->total;
}

Related

How to get total number of rows, and latest row's value in MySql?

I have two tables named Posts and Comments.
Posts table looks like.
|id|user_id|content|created_at|updated_at|
|1 | 24 |demotxt|demo_date |demo_date |
|2 | 21 |domotxt|demo_date2|demo_date2|
|3 | 24 |domotxt|demo_date2|demo_date3|
|4 | 28 |dimotxt|demo_date3|demo_date5|
Comments table looks like
|id|user_id|post_id|comment |created_at|updated_at|
|1 | 24 | 3 |comment1|demo_date |demo_date |
|2 | 21 | 3 |xyadbsss|demo_date2|demo_date2|
|3 | 24 | 1 |okayokay|demo_date2|demo_date3|
|4 | 28 | 4 |somehtin|demo_date3|demo_date5|
What I am trying to achieve is to get first latest comment and total number of comments for each post. i.e.
|post_id|latest_comment |total_comments |
| 3 |xyadbsss |2 |
| 1 |okayokay |1 |
| 4 |somehtin |1 |
This is the sql query I have tried
SELECT post_id, count(post_id) total_comments, comment latest_comment
FROM `comments`
LEFT JOIN posts on comments.post_id = posts.id
GROUP BY post_id;
Which is giving me
|post_id|latest_comment |total_comments |
| 3 |comment1[not latest]|2 |
| 1 |okayokay |1 |
| 4 |somehtin |1 |
Can you try something like this, not sure if is best solution.
SELECT
c1.post_id,
count(c1.`post_id`) total_comments,
(
SELECT
c2.comment
FROM
comments as c2
WHERE
c2.post_id = c1.`post_id`
ORDER BY
c2.id DESC LIMIT 1
) as latest_comment
FROM
`comments` as c1
GROUP BY
c1.`post_id`;
I would rather loop the first data and do another query based on post id to get latest comment.
To get the latest record in database you can use this
Model::latest()->first();
So in your case to get the latest comment:
Comment::latest()->first()['comment'];
You can also use this method depending of your laravel version (if you use 5.7 or higher):
DB::table('comments')->latest('comment')->first();
Now to count all comments on a post you can looking for all comments with the post id and use the count property
$count = Comment::where('post_id',$the_id_of_the_post)->count();
One way to achieve this would be to use the latestOfMany method. Add the following to your Post model:
public function latestComment()
{
return $this->hasOne(Comment::class)->latestOfMany();
}
Then you can eager load the results:
$posts = Post::with('latestComment')->withCount('comments as total_comments')->get();

Laravel Eloquent, How to access eloquent on 3 tables with where?

I have 3 tables like this below :
Items table
id | name
1 | Laptop
2 | Computer
3 | Tv
Production table
id | date
1 | 2021-10-01
2 | 2021-10-03
3 | 2021-10-30
Detail table
id | production_id| item_id |qty
1 | 1 | 1 | 5
2 | 1 | 3 | 10
3 | 2 | 1 |2
4 | 2 | 2 |3
5 | 2 | 3 |23
And what I'm trying to achieve is like this :
(where Production dateBetween this date and that date)
Items |Sum qty
Laptop | 7
Computer | 3
Tv | 33
How to do this in eloquent way ?
Should I use hasManyThrough relationship ?
Thank you for your kind help.
Since this is concatenation problem, i would not use standard relationships for this. Instead let mysql solve this, by creating a custom query in the ORM.
The strategy is to join all the rows, group it by the name of the product. Sum the quantity and create the where condition for the dates.
$items = Item::select('name', DB::raw('SUM(details.qty) as quantity'))
->join('details', 'items.id', '=', 'details.item_id')
->join('productions', 'productions.id', '=', 'details.production_id')
->whereBetween('productions.date', [now()->subMonth(), now())
->groupBy('details.name')
->get();
You could loop the data like so.
foreach ($items as $item) {
$item->name;
$item->quantity;
}

Use result of a rails where query for another query

I'm curious if there is an easy way to archive this query:
SomeTable.where(value_b: SomeTable.where(value_a: 1).pluck(:value_b))
For an example, if we have:
SomeTable
|id | a | b |
|1 | 1 | 2 |
|2 | 2 | 2 |
|3 | 3 | 3 |
|4 | 4 | 4 |
And the user enter number 1 into the system, I want to be able to find value of b where value of a = 1, which is 2. Then use this value of b to find all the records with this value.
So, I want to be able to use 1 and extract SomeTable with id: 1 and 2
Thanks!
SomeTable.joins("JOIN some_table as replica on replica.value_b = some_table.value_b")
.where(replica: {value_a: 1})
SomeTable.where("b in (SELECT b FROM some_tables where a = ?)", a_value)
a_value is your 'a' value to find 'b' value

multicount on SQl query

I am looking for the proper SQl query to pull data from a the database and COUNT the specific rows to come up with a total... here's my table:
------------------------------------------
|name |App |Dep |Sold |
------------------------------------------
|Joe |1 |1 |2 |
|Joe |1 |2 |2 |
|Steve |1 |1 |1 |
|Steve |1 |2 |1 |
------------------------------------------
So I need to count the "1" in each column for each name and come up and output the totals like this:
Joe | 2 App | 1 Dep | 0 Sold
Steve | 2 App | 1 Dep | 2 Sold
Anyone have a starting point for me? I'm not sure if i need JOINs or i can just add seperate COUNTs for each column?
SELECT Name,
SUM(App = 1) TotalApp,
SUM(Dep = 1) TotalDep,
SUM(Sold = 1) TotalSold
FROM tableName
GROUP BY Name
SQLFiddle Demo
App = 1 is a mysql specific syntax which performs boolean arithmetic resulting 1 and 0. To make it more RDBMS friendly, you can use CASE eg. SUM(CASE WHEN App = 1 THEN 1 ELSE 0 END).
SQL Fiddle Demo using CASE statement

SQL: Compare if column values in two tables are equal

I'm working on mysql and have two tables with the same schema:
preTrial
|id|accusedId|articleid|
------------------------
|1 | 1 | 1 |
|2 | 1 | 2 |
|3 | 1 | 3 |
|4 | 2 | 1 |
|5 | 2 | 2 |
trial
|id|accusedId|articleid|
------------------------
|1 | 1 | 1 |
|2 | 1 | 2 |
|3 | 2 | 1 |
|4 | 2 | 2 |
I want to get those accusedIds where all the articleIds of the first and the second tables are equal.
The above example should only return the accusedId 2, cause for accusedId 1 there is no articleId 3 in the second table.
I hope you understand what i mean. I'm currently writing my thesis in law, and the the time i was into sql is long gone by. Of course i already did some research, and tried several joins, but i was not able to find a solution. Hopefully you can help me.
Try something like this:
select a.accusedId , sum(a.accusedid) as cnt_a, sum(coalesce(b.accusedId, 0)) as cnt_b
from a left join b on a.accusedId = b.accusedId and a.articleId = b.articleId
group by accusedId
having cnt_a = cnt_b
I haven't even run that, so it might be a little off, but give it a lash. What it's doing is returning zeroes for a row in a not matched by b, so the HAVING clause will filter your grouped results to those where the article counts are equal.