SQL Query / find percentile based on rank - mysql

I have created the following tables with ranks for a data set:
Position Index IndexL IndexH Amount Rank
1 2.5 2 3 2000 1
1 2.5 2 3 3000 2
1 2.5 2 3 4000 3
1 2.5 2 3 5000 4
1 2.5 2 3 6000 5
2 1.5 1 2 2500 1
2 1.5 1 2 4500 2
2 1.5 1 2 6700 3
2 1.5 1 2 8900 4
2 1.5 1 2 9900 5
Now I want to find the percentile based on the ranks created using the indices such that I get the following output :
Position Amount
1 3000+(4000-3000)*(2.5-2)
2 2500+(4500-2500)*(1.5-1)
Can someone help me with this. I am kinda new to SQL world.
Thanks,
Monica

I think you can do what you want with the percentile_cont() aggregation function. It looks like you want the median:
SELECT position,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY Amount) as Median
from t
group by position;
You can read more about it here.

You can have Oracle assign a percentile for you using the NTILE analytic function:
SELECT
position,
amount,
NTILE(100) OVER (PARTITION BY POSITION ORDER BY amount)
FROM myTable
I'm not sure if the result will match your calculations (I'm a bit hazy on some of my statistics). If not, please try the PERCENTILE_CONT solution proposed by #GordonLinoff, or else you can try the PERCENT_RANK analytic function - just replace NTILE(100) in the query above with PERCENT_RANK().

Related

Get Quater using number as input in MySql

i have a column that has month number stored as integer. i would like to create a new column with the quater of each month. is there an simpler way of doing the same, i have to use this in multiple places. so just wanted to check if there is any simpler way of doing this.
currently i am using below to achieve it
case when tt1.resolved_month in (1,2,3) then 1
when tt1.resolved_month in (4,5,6) then 2
when tt1.resolved_month in (7,8,9) then 3
when tt1.resolved_month in (10,11,12) then 4
end as quater
i checked the Quarter function and it doesnt support number as input.
CEIL function will get the quarter.
SELECT CEIL(resolved_month / 3) AS quarter
Demonstration:
Month Month/3 Quarter
-------------------------
1 0.3333 1
2 0.6667 1
3 1 1
4 1.3333 2
5 1.6667 2
6 2 2
7 2.3333 3
8 2.6667 3
9 3 3
10 3.3333 4
11 3.6667 4
12 4 4
Working Fiddle
Instead of a case expression, you could divide the month by 3 and ceil the result:
SELECT CEIL(resolved_month / 3) AS quarter
FROM tt1
As #exudong suggested in the comments, it may be a good idea to encapsulate this logic in a function and re-use it wherever needed.
You could use the QUARTER() function:
SELECT
resolved_month,
QUARTER(ADDDATE('2021-01-01',INTERVAL resolved_month-1 MONTH)) as quarter2
FROM months;
Fiddle
The advantage (😉) is that everybody who read this will recognize that the quarter is being calculated.

MySQL: Get count for each range

There is mysql Ver 8.0.18 value_table as:
value count
1 3
11 1
12 2
22 5
31 1
34 3
35 1
40 3
46 7
What is query to get a total count for each dozen (1-10 - first dozen,11-20 - second , etc..)
as:
1 3
2 3
3 5
4 8
5 7
Query should be flexible, so when some records added to value_table , for example
51 2
62 3
so, it is not necessary to change a query by adding new range (51-60 - 6-th dozen, etc.)
I think you just want division and aggregation:
select min(value), sum(count)
from t
group by floor(value / 10);
To be honest, I'm not sure if the first column should be min(value) or floor(value / 10) + 1.

mysql if condition add value else add value1

I'am trying to get total full time and total half time by user, Timing is stored in single column, Integer value of timing should come in full time as sum(timing) and floating value in half time but in count
id user_id timing
1 2 1
2 2 2.5
3 1 1.5
4 1 1
5 3 3
6 2 2.5
I need the result as
user_id fulltime halftime
1 2 1
2 5 2
3 3 0
SELECT user_id
, SUM(FLOOR(timing)) AS fulltime
, SUM((timing % 1) * 2) AS halftime
FROM table
GROUP BY user_id;
This query should help you. please try it on your data
SELECT user_id,
sum(if(ceil(timing)>timing,0,timing)) as fulltime,
sum(if(ceil(timing)>timing,timing,0)) as halftime
FROM rest
GROUP BY user_id
Thanks
Amit

MySQL: Matching inexact values using "ON"

I'm way out of my league here...
I have a mapping table (table1) to assign particular values (value) to a whole number (map_nu). My second table (table2), is a collection of averages (avg) for each user (user_id).
(I couldn't figure out how to properly make a markdown table, please feel free to edit!)
table1: table2:
(value)(Map_nu) (user_id)(avg)
---- -----
1 1 1 1.111
1.045 2 2 1.2
1.09 3 3 1.33333
1.135 4 4 1
1.18 5 5 1.389
1.225 6 6 1.42
1.27 7 7 1.07
1.315 8
1.36 9
1.405 10
The value Map_nu is a special number that each user gets assigned according to their average. I need to find a way to match the averages from table2 to the closest value in table1. I only need to match to the 2 digit past the decimal, so I've added the Truncated function
SELECT table2.user_id, map_nu
FROM `table1`
JOIN table2 ON TRUNCATE(table1.value,2)=TRUNCATE(table2.avg,2)
I still miss the values that don't match the averages exactly. Is there a way to pick the nearest truncated value or even to round to the second decimal? Rounding up/down wont matter as long as its applied to all values the same.
I am trying to have the following result (if rounded up):
(user_id)(Map_nu)
----
1 4
2 6
3 6
4 1
5 10
6 11
7 3
Thanks!
i think you might have to do this in 2 separate queries. there is no 'nearest' operator in sql, so you can either calculate it in your software, or you could use
select map_nu from table1 ORDER BY abs(value - $avg) LIMIT 1
inside a loop. however, that cannot be used as a join function as it requires the ORDER and LIMIT which are not valid as joins.
another way of looking at it is it seems that your map_nu and value are deterministic in relation to each other - value = 1 + ((map_nu - 1) * 0.045) - so maybe you could make use of that fact and calculate an integer based on that equation? assuming that relationship holds true for all values of map_nu.
This is an awkward database design. What is the data representing and what are you trying to solve? There might be a better way.
Maybe do something like...
SELECT a.user_id, b.map_nu, abs(a.avg - b.value)
FROM
table2 a
join table1 b
left join table1 c on abs(a.avg - b.value) > abs(a.avg - c.value)
where c.value is null
order by a.user_id
Doesn't actually produce the same output as the one you were expecting for (doesn't do any rounding). Though you should be able to tweak it from there. Above query will produce the output below (w/ data you've provided):
user_id map_nu abs(a.avg - b.value)
------- ------ --------------------
1 3 0.0209999999999999
2 5 0.02
3 8 0.01833
4 1 0
5 10 0.016
6 10 0.0149999999999999
7 3 0.02
Beware though if you're dealing with large tables. Evaluate the explain of the above query if it'll be practical to run it within MySQL or if better to be done outside it.
Note 2: Will produce duplicate rows if there are avg values that are equi-distant to value values within table1 (Ex. if value for map_nu's 11 and 12 are 2 and 3 and someone get's an avg of 2.5). Your question doesn't really specify what to do for that so you might want to take that into account.
Its taking a little extra work, but I figure the easiest way to get my results will be to map all values to the second decimal place in table1:
1 1
1.01 1
1.02 1
1.03 1
1.04 1
1.05 2
1.06 2
1.07 2
1.08 2
1.09 3
1.1 3
1.11 3
1.12 3
1.13 3
1.14 4
...
Thanks for the suggestions! Sorry I couldn't present the question more clear.

mysql query to get charges

I have the table below
relID value charge
1 2 5
1 8 2
2 1 10
2 4 6
2 9 2
For the above table i need for a given value ex 10 to find what to charge for each relID
In the above for value<10 i need to get charge=5 for relID=1 and charge=2 for relID=2
I am trying to use 1 sql command to get it and i am kind of lost
Can anyony help
Thanks
Your question isn't very clear but I think this will work for you
SELECT t.relID,
(
SELECT charge
FROM table
WHERE relID = t.relID
AND value < 10
ORDER BY value
LIMIT 1
) AS charge
FROM table AS t
Let me rephrase.
Here is the table
relID value charge
1 2 5
1 8 2
2 1 10
2 4 6
2 9 2
Explain the table :
Lets say that the value and charge are money.
If the user has value 2 then i must charge with 5 using relID 1
If the user has value 8 then i must charge with 2 using relID 1
same for the relID 2
So when a user come with a value 10 i must find what to charge.So for the given value 10 i must find in the table all records with value<10.
In the example the values for value <10 are
For relID=1 are (2,8)
For relID=2 are (1,4,9)
Now for each relID i need to get the max value.
For relID=1 max value is 8 so charge is 2
For relID=2 max value is 9 so charge is 2
I plain english there are value rate
0-2 charge 5
2-8 charge 2
and ...
i hope to be clear now
select *
from Table t
where value =
(select max(value)
from Table
where value <= 10
and relId = t.relId)