Laravel - SUM and balane query - mysql

I have a Laravel application. I am trying calculate the SUM of column and balance. Can you please help me how to write the SQL for this.
+---------+----------+--------+----------+----------+------------+
| pay_id | username | income | outgoings| balance | date |
+---------+----------+--------+----------+----------+------------+
| 1 | john | 1000 | | 1000 | 00.00.2016 |
| 2 | jack | | 500 | 500 | 00.00.2016 |
| 3 | john | 1500 | | 2000 | 00.00.2016 |
| 4 | bill | | 1000 | 1000 | 00.00.2016 |
+---------+----------+--------+----------+----------+------------+
2500 1500

If you're using Eloquent:
Model::where('username', 'john')->sum('balance');
https://laravel.com/docs/5.3/eloquent#retrieving-single-models

If you want to sum multiple columns then you have to us DB::raw
$data = Model::get([
DB::raw('SUM(income) AS total_income'),
DB::raw('SUM(outgoings) AS total_outgoings'),
DB::raw('SUM(balance) AS total_balance')
]);
dd($data);
Or
$data = Model::select(
DB::raw('SUM(income) AS total_income'),
DB::raw('SUM(outgoings) AS total_outgoings'),
DB::raw('SUM(balance) AS total_balance')
)
->get();
dd($data);

Related

Yii2 findBySql: How to specify $params?

Yii2 provides ActiveRecord::findBySql für raw SQL queries:
public static yii\db\ActiveQuery findBySql ( $sql, $params = [] )
Since there is no hint in the documentation: How to specify $params?
UPDATE
The reason there isn't any docs about the params passed to the findBySql() method is because the method returns the instance of ActiveQuery and if you see the last line of this method in yii\db\ActiveRecord.php it sets the $params via $query->params($params), means the yii\db\ActiveQuery function params($params) which defines the $params as
$params list of query parameter values indexed by parameter
placeholders. For example, [':name' => 'Dan', ':age' => 31].
I guess you should try the following way if lets say you have a table with name product
+----+-----------------+------------+--------+
| id | name | is_deleted | price |
+----+-----------------+------------+--------+
| 1 | shugal | 1 | 65.00 |
| 2 | spoon | 1 | 55.00 |
| 4 | kettle | 1 | 15.00 |
| 5 | spoon | 0 | 15.00 |
| 6 | plates | 0 | 105.00 |
| 7 | dishes | 0 | 15.00 |
| 8 | forks | 0 | 15.00 |
| 10 | pressure cooker | 0 | 203.00 |
| 16 | shugal | 1 | 65.00 |
| 17 | something | 0 | 25.00 |
| 25 | multi product | 0 | 0.00 |
| 66 | pans | 0 | 15.00 |
+----+-----------------+------------+--------+
using the following code you can select all the products that are deleted using params
$q = Product::findBySql(
"SELECT * FROM product where is_deleted=:deleted",
[':deleted' => 1]
)->all();
Hope this helps

Get the DISTINCT id of users and find the MAX of their column then UPDATE, LARAVEL

What I want to do is, the distinct id based on the max value of the associated column and then update a column accordingly.
For example
id | name | total | description | updateThis
1 | john | 100 | example | 0
2 | dave | 300 | example | 0
2 | johno | 500 | example | 0
4 | derik | 900 | example | 0
5 | Sam | 1000 | example | 0
4 | bool | 12200 | example | 0
1 | john | 1200 | example | 0
5 | john | 300 | example | 0
I want it to look like this:
id | name | total | description | updateThis
1 | john | 1200 | example | 1
2 | johno | 500 | example | 1
4 | bool | 12200 | example | 1
5 | Sam | 1000 | example | 1
I am using Query Builder not the eloquent way of doing it, either would be a useful answer and if someone can give both that would be awesome too, I just need help thanks.
You can use this:
$rows = DB::table('table')
->select('id', DB::raw('max(total) as total'))
->groupBy('id')
->get();
foreach($rows as $row) {
DB::table('table')
->where('id', $row->id)
->where('total', $row->total)
->update(['updateThis' => 1]);
}

Complicated loop of queries into a single one

I need a little bit of help with making a complicated query, i will try to explain what i am trying to accomplish down below.
Here is my data
table_one
+---------+---------+----------+----------+
| user_id | poly_id | in | out |
+---------+---------+----------+----------+
| 900 | 1 | 20-12-17 | 20-12-17 |
| 900 | 2 | 21-12-17 | 22-12-17 |
| 900 | 3 | 22-12-17 | 24-12-17 |
| 900 | 1 | 23-12-17 | 26-12-17 |
| 444 | 4 | 24-12-17 | 28-12-17 |
| 444 | 4 | 25-12-17 | 30-12-17 |
| 444 | 5 | 26-12-17 | 01-01-18 |
| 444 | 3 | 27-12-17 | 03-01-18 |
| 900 | 2 | 28-12-17 | 05-01-18 |
| 900 | 1 | 29-12-17 | 07-01-18 |
| 444 | 2 | 30-12-17 | 09-01-18 |
+---------+---------+----------+----------+
table_two
+----+---------+-------------+---------+
| id | name | type | product |
+----+---------+-------------+---------+
| 1 | city 1 | gas station | general |
| 2 | city 2 | workshop | general |
| 3 | city 3 | paint | bikes |
| 4 | city 4 | paint | general |
| 5 | city 5 | gas station | cars |
| 6 | city 6 | gas station | bikes |
| 7 | city 7 | paint | cars |
| 8 | city 8 | workshop | cars |
| 9 | city 9 | gas station | general |
| 10 | city 10 | gas station | cars |
| 11 | city 11 | gas station | general |
+----+---------+-------------+---------+
i have a working solution that looks like this
//results comes from somewhere else, it looks something like this for example:
array (
"user_id" => "poly_id of the last gas station"
"900" => 1,
"444" => 10
)
foreach ($result AS $res ) {
$query = "
SELECT
table_one.name AS name
FROM
`table_one`
LEFT JOIN
`table_two` ON table_one.poly_id = table_two.id
WHERE
`table_two`.type = 'gas station '
AND
table_one.user_id = $res['user_id']
AND
table_one.poly_id != $res['poly_id']
AND
table_one.in >= "some date from'
AND
table_one.out <= 'some date to'
AND
(FIND_IN_SET('general', table_two.product) > 0 OR FIND_IN_SET('cars', table_two.product) > 0 )
ORDER BY out DESC LIMIT 1
";
//if the results is not empty use the result['name']
}
The idea is: I have the user last gas station, but i need to find the previous one between a date range.
As i said, the above example is working just fine, however i need to be able to process multiple results at once, and sometimes the results are ~2000.
Which means 2000+ queries per request.
Is it even possible to somehow optimize this loop of queries into a single one, so I don't do 2000 queries per request ?
If possible, how :D
Thanks.
This query will return result contains user_id with it's last
enter in the given periode.
one thing here because you are
using date not date time if the user exit in the same
day two time you will have two record of that user you can skip the second
record in you code
select
user_id,
in,
out
from table_one t1
INNER JOIN (
select
user_id
max(out) as 'max_out',
from
table_one
where
in >= ? AND
out <= ? AND
ploy_id not in [list_of_unwanted_ploy_id]
-- you can specify any condition here
group by user_id
) l_out on t1.user_id = l_out.user_id and t1.out = l_out.max_out
where
t1.user_id in [list_of_user_id]

How to get sum for different entry in mysql

I have table in mysql like
| service_code | charges | caller_number | duration | minutes |
+--------------+---------+---------------+----------+---------+
| 10 | 15 | 8281490235 | 00:00:00 | 1.0000 |
| 11 | 12 | 9961621709 | 00:00:00 | 0.0000 |
| 10 | 15 | 8281490235 | 01:00:44 | 60.7333 |
| 11 | 2 | 9744944316 | 01:00:44 | 60.7333 |
+--------------+---------+---------------+----------+---------+
from this table I want to get charges*minutes for each separate caller_number.
I have done like this
SELECT sum(charges*minutes) as cost from t8_m4_bill groupby caller_number
but I am not getting expected output. Please help?
SELECT caller_number,sum(charges*minutes) as cost
from t8_m4_bill
group by caller_number
order by caller_number

how to insert average of a query into mysql table

I am trying to get average of latency for each items that holds into two separate mysql table. Let me more clarify that I have two mysql tables as below,
table: monitor_servers
+-----------+-----------------+
| server_id | label |
+-----------+-----------------+
| 1 | a.com |
| 2 | b.com |
+-----------+-----------------+
table: monitor_servers_uptime
+-------------------+-----------+-----------+
| servers_uptime_id | server_id | latency |
+-------------------+-----------+-----------+
| 1 | 1 | 0.4132809 |
| 3 | 1 | 0.4157769 |
| 6 | 1 | 0.4194210 |
| 9 | 1 | 0.4140880 |
| 12 | 2 | 0.4779439 |
| 15 | 2 | 0.4751789 |
| 18 | 2 | 0.4762829 |
| 22 | 2 | 0.4706681 |
+-------------------+-----------+-----------+
Basically, each domains associated with the same id_number in both tables. While I am running the query below, getting average of each items.
select monitor_servers.label, avg(monitor_servers_uptime.latency)
from monitor_servers,monitor_servers_uptime
where monitor_servers.server_id = monitor_servers_uptime.server_id
group by monitor_servers.server_id;
The query ended up,
+---------------------+-------------------------------------+
| label | avg(monitor_servers_uptime.latency) |
+---------------------+-------------------------------------+
| a.com | 0.41393792995 |
| b.com | 0.47551423171 |
+---------------------+-------------------------------------+
My questions are doing am i in wright way while getting average of the each items and how can i insert new average result of each items into a new column on table monitor_servers ? And also what happens if some of latency rows are NULL ?
**Edit : What i am trying to achieve in one query result is **
+-----------+----------+------------------+
| server_id | label | avg. |
+-----------+----------+------------------+
| 1 | a.com | 0.41393792995 |
| 2 | b.com | 0.47551423171 |
+-----------+-----------------------------+
Thanks in advance,
Your calculation seems to be correct.
You could add another column to the monitor_servers using sql:
ALTER TABLE monitor_servers ADD avg_latency DEFAULT 0.0 NOT NULL
For doing the AVG calculation check this answer.