Group last rows in a single one summing values - mysql

I have this mysql table:
date | client | total
2015-01-01 | john | 85.00
2015-01-01 | alfred | 35.00
2015-01-01 | georgy | 125.00
2015-01-01 | linda | 42.00
2015-01-01 | alex | 76.00
2015-01-01 | john | 94.00
2015-01-01 | john | 75.30
I wanted to group by client name calculating total sum amount and percent, so I made this query:
SELECT client, total, round(total*100/t.th,1) as percent
FROM (
SELECT client, sum(total) as total
FROM mytable
WHERE date='2015-01-01'
GROUP BY `client`) c
JOIN ( select sum(total) as th from mytable
WHERE date='2015-01-01') t
order by percent desc
It works great obtaining this result:
client | total | percent
john | 254.3 | 47.8
georgy | 125 | 23.5
alex | 76 | 14.3
linda | 42 | 7.9
alfred | 35 | 6.6
But I don't know if it's possible to sum last rows and group in a single one obtaining a result like this, for example:
client | total | percent
john | 254.3 | 47.8
georgy | 125 | 23.5
others | 135 | 28.8
I would like to know how can I modify my query to obtain this result.
I'd like some help.

Related

Joining two MySQL datasets by date as well as id

I am struggling to find a way to efficently join two datasets using a single query
Dataset one can be returned using the following query:
SELECT hours_person_id, hours_date, hours_job, SUM(hours_value) AS hours
FROM hours
WHERE hours_status = 1
GROUP BY hours_person_id, hours_date, hours_job
which gives a dataset similar to
| 1 | 2020-06-07 | 101 | 25 |
| 1 | 2020-06-07 | 102 | 10 |
| 1 | 2020-06-07 | 103 | 5 |
| 2 | 2020-06-07 | 101 | 30 |
| 2 | 2020-06-07 | 104 | 10 |
From which we can get total hours per week, per job, etc...
Our second dataset gives us the hourly rates for the each person. The problem is that this table contains both historical and future hourly rates, so the join needs to ensure that the rate applies to the correct person_id and date. There could also be more than 1 rate for a person on a date.
The following gives all the rates that are active
SELECT rate_person_id, rate_date, rate_value
FROM rates
WHERE rate_active = 1
Which could look like
| 1 | 2020-01-01 | 20.00 |
| 1 | 2020-05-01 | 25.00 |
| 1 | 2020-07-01 | 22.00 |
| 2 | 2020-01-01 | 22.00 |
| 2 | 2020-05-01 | 24.00 |
| 3 | 2020-05-01 | 20.00 |
| 3 | 2020-05-01 | 21.00 |
| 3 | 2020-07-01 | 18.00 |
So for the hours above the rate from the 2020-05-01 would be the expected result, with the 21.00 value being the result for person_id === 3
Can what I am looking for be done in a single Query, or am I better off Joining two subqueries?
Update
As requested here is a fiddle that represents the above
https://www.db-fiddle.com/f/oiUpTnajY6M6ZTfZgRf4kT/0
As you can see we have a query that returns the correct data, but this query does not scale to our curennt data set (1.8m lines and more sub tables)
So for the hours above the rate from the 2020-05-01 would be the expected result, with the 21.00 value being the result for person_id === 1
From your rates output, person_id = 1 was never on rate value 21.00 .
| 1 | 2020-01-01 | 20.00 |
| 1 | 2020-05-01 | 25.00 |
| 1 | 2020-07-01 | 22.00 |
For 2 active rates for a person, do you need the most recent rate or you need the rate in the month where he worked. If there is no rate for that month then do you want 0 rate or something else.
SELECT h.*,
(SELECT rate_value
FROM rates r
WHERE h.hours_person_id = r.rate_person_id AND
r.date <= h.date
ORDER BY r.date DESC
LIMIT 1
) as rate_value
FROM hours h
I don't see what active has to do with the question, because you need to go back in time. You can then aggregate or do whatever you want once you have the correct rate on the date.

MySQL Min Max deduction

I have a simple table that used to store fuel issuing details for different vehicles as follows:
+----+------------+-----+---------------+-------------+
| id | vehicle_no | qty | meter_reading | date_issued |
+----+------------+-----+---------------+-------------+
| 1 | 366 | 50 | 10500 | 2019-09-01 |
| 2 | 366 | 50 | 11020 | 2019-09-02 |
| 3 | 367 | 25 | 25000 | 2019-09-03 |
| 4 | 366 | 50 | 11450 | 2019-09-04 |
| 5 | 368 | 50 | 6000 | 2019-09-05 |
+----+------------+-----+---------------+-------------+
02) Then I need to find no of Kilometers run against issued sum of fuel quantities.
03) I used the following query
select f1.vehicle_no, (select f1.meter_reading-f2.meter_reading)/sum(qty) from fuel f1) from fuel f2 group by vehicle_no
04) I want to get the desired output as follows :
As an example :
the meter reading of id=4 - meter reading of id=2 is 430 Kilometers
the meter reading of id=4 - meter reading of id=1 is 950 Kilometers
the meter reading of id=2 - meter reading of id=1 is 520 Kilometers
But I did not get the expected result. Can anyone help me ?
With a self join:
select
f.id,
ff.id,
f.vehicle_no,
f.date_issued,
ff.date_issued,
f.meter_reading - ff.meter_reading as dif
from fuel f inner join fuel ff
on ff.vehicle_no = f.vehicle_no and ff.date_issued < f.date_issued
See the demo.
Results:
> id | id | vehicle_no | date_issued | date_issued | dif
> -: | -: | ---------: | :------------------ | :------------------ | --:
> 2 | 1 | 366 | 2019-09-02 00:00:00 | 2019-09-01 00:00:00 | 520
> 4 | 1 | 366 | 2019-09-04 00:00:00 | 2019-09-01 00:00:00 | 950
> 4 | 2 | 366 | 2019-09-04 00:00:00 | 2019-09-02 00:00:00 | 430

how to query sum for one field of two mysql tables

I have two mysql table.
Table: bill
id | billtype | amount | advid | paydate |adjid | adjdate |
1 | electric | 10000 | 123 | 2017-01-01 | 50 | 2017-01-03 |
2 | Water | 5000 | 124 | 2017-02-01 | 0 | 0000-00-00 |
3 | Shirt | 500 | 125 | 2017-03-01 | 0 | 0000-00-00 |
Table: advance
id | advid | amount | balance | purpose |
1 | 123 | 50000 | 20000 | Bill |
2 | 124 | 70000 | 10000 | Bill |
3 | 125 | 55000 | 15000 | Uniform |
4 | 124 | 60000 | 10000 | Bill |
I want to create a drop down menu so that to select those 'advance' which are not adjusted yet (adjid=0 and adjdate=0000-00-00) in Table: bill and that drop down menu will also contain the total value of advance for same advance id (advid) like below:
<option>Bill-130000</option>
<option>Uniform-55000</option>
As total 130000 (70000+60000) advance is taken against advance id 124, so the Total amount of Advance in Option menu should be 130000 in case of Bill. But I am failed to calculate total amount of advance accurately:
SELECT sum(a.amount), purpose FROM bill as b, advance as a WHERE b.paydate!='0000-00-00' AND b.adjid!=0 AND a.advid=b.advid GROUP BY a.advid
Total amount in <option></option> is not coming actual.
What would be the right query for this purpose?
You could try
SELECT SUM(a.amount) AS amount,
MAX(purpose) AS purpose
FROM advance a
WHERE a.advid IN (
SELECT b.advid
FROM bill b
WHERE b.paydate = '0000-00-00'
AND b.adjid = 0)
GROUP BY a.advid

POS Application - Simplify SQL Mutli-Queries(MySQL)

Hei guy I'm working on a POS app with MySQL. Here is my situation:
Table "purchased_item"
| id | name | check_id | real_price |
| 1 | iPhone5 | 0001 | 399 |
| 2 | iPhone4 | 0001 | 199 |
| 3 | iPhone5s | 0002 | 599 |
| 4 | iPhone5c | 0003 | 399 |
| 5 | iMac 21" | 0003 | 999 |
| 6 | iPod Touch | 0003 | 99 |
| 7 | iPhone5 | 0004 | 399 |
| 8 | iPhone3G | 0004 | 99 |
| 9 | iPhone6 | 0005 | 899 |
| 10 | iPhone3Gs | 0005 | 101 |
And I want to know how many checks's total are larger than or qual(>=) 1000, so what I'm doing now is to do several times of query. In this example, I do 5 times and sum it manually by the host program.
Later the data grow, the queries become slow because there're tons of checks everyday. So I change to record it to another table.
Table "checks"
| id | total | sales |
| 0001 | 598 | A |
| 0002 | 599 | A |
| 0003 | 1497 | B |
| 0004 | 498 | B |
| 0005 | 1000 | A |
But another problem occur in the later time: When I need to adjust the real_price in "purchased_item" table, I also need to maintain the "total" column in "checks" table. It sounds doesn't a big matter but I'd like to find a better way to solve it.
Solved:
SELECT * FROM purchased_item
GROUP BY check_id
HAVING sum(real_price) >= 1000
And the result will be:
| id | name | check_id | real_price |
| 4 | iPhone5c | 0003 | 399 |
| 9 | iPhone6 | 0005 | 899 |
Further question: If I want to count the total price for checks, how can I do it?
I found it:
SELECT check_id,sum(real_price) FROM purchased_item
GROUP BY check_id
HAVING sum(real_price) >= 1000
Try it this way
SELECT i.id, i.name, i.check_id, i.real_price
FROM
(
SELECT MIN(id) id
FROM purchased_item
GROUP BY check_id
HAVING SUM(real_price) >= 1000
) q JOIN purchased_item i
ON q.id = i.id
ORDER BY q.id DESC
Sample output:
| ID | NAME | CHECK_ID | REAL_PRICE |
|----|----------|----------|------------|
| 9 | iPhone6 | 5 | 899 |
| 4 | iPhone5c | 3 | 399 |
...I want to count how many checks's total are over 1000
For that you can just do this
SELECT COUNT(*) total
FROM
(
SELECT check_id
FROM purchased_item
GROUP BY check_id
HAVING SUM(real_price) >= 1000
) q;
Sample output:
| TOTAL |
|-------|
| 2 |
Here is SQLFiddle demo
To update total in checks after adjusting real_price in purchased_item
UPDATE checks c JOIN
(
SELECT check_id, SUM(real_price) total
FROM purchased_item
WHERE check_id IN(5) -- whatever check(s)'s total you want to recalculate
GROUP BY check_id
) p
ON c.id = p.check_id
SET c.total = p.total;
Here is SQLFiddle demo

Subtracting sums in one table from sums in another

I have two mysql tables: earning and redemption. Data in the earning table adds to a running balance and data in the redemption table subtracts from that balance. Each table has an hours column and an amount column.
(There are various reasons why these aren't negative and positive values in the same table, but even with these reasons I recognize now that this is likely a poor schema design, but... for now I'm stuck with it).
How can I get a current balance for both the hours and amounts fields? More specifically, how can I write a single query that will give me SUM(earning.hours) - SUM(redemption.hours) and SUM(earning.amount) - SUM(redemption.amount), grouped by a Common_ID?
Some sample data. Other fields exist in each table, but I'm not concerned with them at the moment.
Earning:
+----+-----------+-------+--------+
| id | common_id | hours | amount |
+----+-----------+-------+--------+
| 1 | 234 | 1.03 | 15.75 |
| 2 | 234 | 2.06 | 33.00 |
| 3 | 237 | 2.11 | 12.29 |
| 4 | 237 | 3.50 | 18.63 |
+----+-----------+-------+--------+
Redemption:
+----+-----------+-------+--------+
| id | common_id | hours | amount |
+----+-----------+-------+--------+
| 1 | 234 | 2.50 | 30.00 |
| 2 | 234 | 0.50 | 5.68 |
| 3 | 237 | 1.00 | 8.00 |
+----+-----------+-------+--------+
Desired result:
+-----------+---------------+----------------+
| common_id | hours_balance | amount_balance |
+-----------+---------------+----------------+
| 234 | 0.09 | 13.07 |
| 237 | 4.61 | 22.92 |
+-----------+---------------+----------------+
You need to perform the grouping separately.
SELECT e.Common_ID,
SUM(e.hours) - MIN(g.SumHours),
SUM(e.amount) - MIN(g.SumAmount)
FROM earning e JOIN (
SELECT Common_ID, SUM(hours) SumHours, SUM(amount) SumAmount
FROM redemption
GROUP BY Common_ID
) g ON e.Common_ID = g.Common_ID
GROUP BY Common_ID
Note: as Lamak pointed out, if you have an common_id that doesn't exists in both tables, you will need a LEFT JOIN and possibly another UNION with a RIGHT JOIN.