mysql- subtract values between rows where column values correspond - mysql

I have a table like:
Number | Event | Weight
1 4 150
1 4 160
2 5 200
2 4 200
3 6 190
3 6 195
For each row, I would like to subtract from its Weight, the Weight of another row where Number and Event matches (if exists). The desired output is:
Number | Event | Weight | DIFF
1 4 150 -10
1 4 160 10
2 5 200 NULL
2 4 200 NULL
3 6 190 -5
3 6 195 5
Is such an operation possible? Not sure if relevant, eventually I would need to turn this query into a view. Thanks in advance.

You need a left join:
select
t.*,
t.weight - tt.weight diff
from tablename t left join tablename tt
on tt.number = t.number and tt.event = t.event and tt.weight <> t.weight

It can be done by simply substracting the column in the joined table. When one of the operands is null, the result of the arithmetic operation is null:
select a.Number, a.Event, a.Weight, a.Weight - b.Weight as DIFF
from a
left join b on a.Number = b.Number and a.Event = b.Event

Related

subtract from values by groups

What is the best way to subtract the lowest value from all values by group?
Something like:
ID Name Value
1 A 10
1 B 40
1 C 100
2 A 20
2 B 80
2 C 90
3 A 4
3 B 7
3 C 8
turn to:
ID Name Value
1 A 0
1 B 30
1 C 90
2 A 0
2 B 60
2 C 70
3 A 0
3 B 3
3 C 4
Use window functions:
select id, name, value - min(value) over (partition by id) as
from t;
If you actually want to update the values, in MySQL, aggregation and join are probably the simplest solution:
update t join
(select id, min(value) as min_value
from t
group by id
) tt
on t.id = tt.id
set value = value - min_value
where min_value <> 0;

MySQL - select avg of list but ignore max and min value

I have a list of values in my database.
k v
1 5000
1 100
1 120
1 3
2 5000
2 100
2 120
2 4
3 10000
3 120
3 100
3 4
4 10
4 120
4 110
4 5000
I want to calculate the average of each k but I need to ignore the highest and lowest value of v for each k. (to remove spikes)
select avg(v) from table where v > min(v) and v < max(v) group by k
results in an :
"Invalid use of group function"
I was thinking that this is a quite common task but I wasn't able to find any ideas from the docs.
Thanks for any advise.
One way to do this without worrying about whether there are duplicate min and max values of v (assuming you only want to ignore one of each) is to take the average as SUM(v)/COUNT(v), but subtracting the min and max values from the computation:
SELECT k, (SUM(v) - MAX(v) - MIN(v)) / (COUNT(v) - 2) AS average
FROM data
GROUP BY k
Output:
k average
1 110
2 110
3 110
4 115
Demo on dbfiddle
select avg(v) , k
from table
group by k
having k <> min (v) and k<> max (v)
First get the min and max v for each k and then left join the table to the results so to get the average of the non matching rows:
select
t.k, avg(t.v) average
from tablename t left join (
select k, min(v) minv, max(v) maxv
from tablename
group by k
) g on g.k = t.k and t.v in (g.minv, g.maxv)
where g.k is null
group by t.k
See the demo.
Results:
| k | average |
| --- | ------- |
| 1 | 110 |
| 2 | 110 |
| 3 | 110 |
| 4 | 115 |
Link: Demo
select t1.k, avg(t1.v) average
from numbers t1 left join (
select k, min(v) minv, max(v) maxv
from numbers
group by k
) t2 on t2.k = t1.k and t1.v in (t2.minv, t2.maxv)
where t2.k is null
group by t1.k

How to count max value in one month from 2 table

I have 2 table on my transaction
Table One
id | date | cust_id | driver_number
1 2019-01-02 1 F 3350 NN
2 2019-04-02 2 AX 111 Z
3 2019-05-02 3 S 787 X
4 2019-05-02 4 T 9090 M
5 2019-06-02 3 P 8989 L
Table Two
driver_number | price
F 3350 NN 350000
AX 111 Z 400000
S 787 X 375000
T 9090 M 900000
P 8989 L 500000
How do I count total transaction from two tables above in one month as per requested .
In example, request for total transaction in May so the result is like below
period | total
May 1275000
Thank you
Using MONTH(T1.date) = 5 and SUM(price) the expected result is achievable
SELECT MONTH(T1.date) AS Period, SUM(price) AS `Total`
FROM TableOne T1
JOIN TableTwo T2 ON T2.driver_number = T1.driver_number
WHERE MONTH(T1.date) = 5
GROUP BY MONTH(T1.date)

SELECTING with multiple WHERE range conditions on same column

I have tables like these:
A table B table
-------------------- -----------------------------------
item_ID | item_Name item_ID | option_ID | option_Value
-------------------- -----------------------------------
1 item_a 2 34 2000
2 item_b 2 45 3400
3 item_c 2 12 1200
4 item_d 3 34 500
5 item_e 3 13 500
6 item_f 4 45 700
I wrote a query to get items, for example which have option 34 = 2000 and option 12 = 1200 is:
SELECT A.item_ID, A.item_name
FROM A
LEFT JOIN B ON A.item_ID = B.item_ID
WHERE B.option_ID IN (34, 1200) AND
B.option_Value IN (1200, 2000) AND
GROUP BY A.item_ID
HAVING COUNT(A.item_ID) >= 2 /* count of option used for search, can be more*/
My problem is for some options I want to get range result , for example: where option id 34 is between 1000 and 2000 and option 12 is lower than 4000
Note : (option_id, option_value) pair is unique and i want to get items that match all of the conditions
How about this?
SELECT A.item_ID, A.item_name
FROM A
LEFT JOIN B ON A.item_ID = B.item_ID
WHERE (B.option_ID=34 AND B.option_value BETWEEN 1000 AND 2000)
OR (B.option_ID=12 AND B.option_value BETWEEN 0 AND 4000)
GROUP BY A.item_ID
HAVING COUNT(A.item_ID) >= 2
Maybe I didn't understand the question completely?
This should give you what you want:
WHERE
B.option_ID = 34 AND B.option_Value BETWEEN 1000 AND 2000
OR
B.option_ID = 12 AND B.option_Value < 4000
There might be a better way to do this if there was some rule according to which you want to filter... Otherwise, just use OR and AND to achieve what you want.

MySQL Left Join: if primary condition does not exist use backup condition return only one

I have seen variations of this question asked but either they didn't apply or I didn't understand the answer/s.
I have two tables one table with charges types with additional cost and one of charges. I want to join them to get the appropriate values. I want to join the tables where the charge is between the startDate and the endDate and on the types. If there is not a match I want it to choose the type -1 (same condition for dates). If there is not a match I don't want it to show up in the results.
I initially was was going to do a normal left join ordered by 'type' desc and then group by 'type' believing that it would only leave me with the first type but I read that MySQL advises against this because the group by can be unpredictable and not always return the first match.
Tables:
startDate | endDate | type | addCost
--------------------------------------
2010-01-01 2010-12-31 1 100
2010-01-01 2010-12-31 2 200
2010-01-01 2010-12-31 -1 50
2011-01-01 2012-02-20 3 350
2011-01-01 2012-02-20 1 150
2011-01-01 2012-02-20 -1 75
chargeDate | type | cost
---------------------------
2010-10-01 1 10
2010-11-01 2 20
2010-12-01 4 40
2011-02-01 3 60
2011-03-01 2 25
2011-04-01 4 25
Desired Results:
chargeDate | type | cost | addCost
---------------------------------
2010-10-01 1 10 100
2010-11-01 2 20 200
2010-12-01 4 40 50
2011-02-01 3 60 350
2011-03-01 2 25 75
I'm using a subquery where I am trying to join charges with charges_types. If the join doesn't succeed, type is null and with coalesce I set type_c as -1, otherwise I set it to type. Then I join this subquery with charges_types again, and on the join clause i use type_c instead of type:
select c.chargeDate, c.type, c.cost, ct.addCost
from
(select
charges.chargeDate,
charges.type,
coalesce(charges_types.type, -1) as type_c,
charges.cost
from
charges left join charges_types
on charges.chargeDate between charges_types.startDate and charges_types.endDate
and charges.type = charges_types.type) c
inner join charges_types ct
on c.chargeDate between ct.startDate and ct.endDate
and c.type_c = ct.type