Select top 5 MySQL after division of two rows - php

I have a rating system that takes the rating of 1-5 then increments the number of votes and adds to a total number of rating. This is problematic for my top 5 leaderboard which currently provides Xml through a php web service from the MySQL database with this query:
FROM ratings ORDER BY totalRating DESC LIMIT 5
Now obviously this isn't going to work.
Is there a way to do the division of totalRating by noRating and THEN return order by?
I'm trying to keep this to the database level. Hopefully it's possible.
Edit:
So let's say my table ratings has two records:
Name | cRating | tRating //current number of ratings and total
Tv1 | 2 | 10
Tv2 | 3 | 9
I need to do tRating / cRating then sort them into the top 5 shows
Desired result is to return the top 5 averagely rated results (sorry for the terrible formatting I'm on my phone)

You can use an arithmetic expression in the order by. So this might do what you want:
order by tRating / nullif(cRating, 0) desc

Related

how to get top 5 results from database along with all matched results

I want to show top 3 results and if is there are any results which match with top 3, they should also be fetched. In the examples below there are top 3 results, 50,40 and 30, but ram also has a mark of 30, so I want to fetch that result as well.
my database sheet table
id
user
marks
1
ram
30
3
sam
30
4
ben
40
2
hari
10
5
joe
50
i want to return top 3 results along with all matching results which is match to last result
id
user
marks
5
joe
50
4
ben
40
3
sam
30
1
ram
30
$top_results = "SELECT * FROM `sheet` ORDER BY `marks` DESC LIMIT 3"
and it only return top 3 not the 4 results
i want to show top 3 results and if is there any results match with top 3 also fetched, in above case there is top 3 results are 50,40 and 30 but ram has also 30. So I want to fetch that result also if it is their along with top 3
I want to show top 3 results and if is there are any results which match with top 3, they should also be fetched.
SELECT t1.*
FROM table t1
JOIN ( SELECT result
FROM table t2
ORDER BY result DESC LIMIT 2,1 ) t3 ON t1.result >= t2.result
how to get top 5 results from database along with all matched results
Adjust LIMIT accordingly - LIMIT 4,1.

Create view from live stats

I created a sistem to input results from a school basketball tournament. The idea is that after the game the operators will input the result in a format that the system fetches to save in the db in a format like the one below:
Date | Team | Score 1Q | Score 2Q | Score 3Q | Score 4Q | Score OT | Final Score | W | L | Won over Team | Lost to Team | Regular Season? | Finals?
I created a PHP page that calculate many stats from the table above, like Total Wins, Win%, Avg Points, Avg. Points per Quarter, % Turn Around Games when loosing on Half Time or 3Q, % Finals games disputed, Times became champions etc, and many more deep stats.
But I was thinking in creating a View with this information calcalated on the DB and in real time, instead of having the script handles it.
But how can I turn the selects needed from the first table into a working second table with all calculations done whenever we make the selection?
Thanks
#decio, I think your idea about creating a view to calculate those stats is not a bad idea. You might be able to do so with the something similar to the following SQL script:
CREATE VIEW result_stats_view AS SELECT SUM(W) as total_wins, SUM(L) as total_losses FROM precalculate_stats_table_name;
This shows the total wins and losses for the season, but you probably get the idea. Check out MySQL aggregate functions (like average, sum, etc.) here:
https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html
Once you have your calculations added to the view then you can simply do query like this to get your calculated data:
SELECT * from result_stats_view

How to calculate the weighted average price of stock trades

Given the following table of stock transactions:
TID |DATE |TIME |SYMBOL|SIDE|QUANTITY |PRICE |OPENPOSITION
339791|2014-11-14|12:45:25|ABEV3 |Buy | -900.00|15.920000| -900
339780|2014-11-21|10:54:37|ABEV3 |Sell| 900.00|16.650000| 0
339775|2014-11-24|14:52:59|ABEV3 |Buy | -1500.00|16.950000| -1500
339725|2017-01-20|14:54:26|ABEV3 |Sell| 1500.00|17.280000| 0
339662|2017-02-03|10:43:31|ABEV3 |Buy | -5900.00|17.020000| -5900
339661|2017-02-03|11:44:57|ABEV3 |Buy | -5900.00|17.229492| -11800
339655|2017-02-03|12:37:08|ABEV3 |Sell| 10800.00|17.250000| -1000
339528|2017-02-15|11:04:07|ABEV3 |Buy |-15000.00|17.580000| -16000
339527|2017-02-15|12:07:30|ABEV3 |Sell| 2300.00|17.610000| -13700
339524|2017-02-15|12:10:36|ABEV3 |Sell| 100.00|17.620000| -13600
339522|2017-02-15|12:44:23|ABEV3 |Sell| 14900.00|17.640000| 1300
339518|2017-02-15|12:49:52|ABEV3 |Buy | -2300.00|17.670000| -1000
339474|2017-02-17|11:45:33|ABEV3 |Buy |-20000.00|17.860000| -21000
339472|2017-02-17|13:36:16|ABEV3 |Sell| 20000.00|17.960000| -1000
How can I generate a mysql query to compute the avg weighted price of a transaction whether it is a buy or sell.
In the example above, the trader started buying 900 shares and selling 900 shares for a position balance of 0 (see second row). He does the same thing with 1500 shares, but then he buys and sells several times and remains with 1000 shares left. When calculated by hand, the avg weighed price of purchase is
5900*17.23+5900*17.02+2300*17.67+15000*17.58+20000*17.86/49100 = $17.59
Is there a way to build a query or php functions that considers only the prices of transactions that are still open?
Yes.
If that information is in a database, you'd write a sql select that would be something like:
SELECT price,quantity FROM stock_transactions WHERE ___
But hat do you mean by past closed? Are they closed if they're before the current date? (today)?
If so it'd be:
SELECT price,quantity FROM stock_transactions WHERE CURDATE() >= '2017-02-22'
That'll get those records.
Then run a result set, run through those in a while loop multiplying your price * quantity, add that (+= not assignment) to a variable (that's declared outside that loop fyi). Then repeat.
Select all rows for the given symbol that have OPENPOSITION = 0, and order them by descending date and time.
Read the first row returned and get the date and time. This will be the lower boundary of records you want.
Select all rows for the given symbol with date and time greater than the lower boundary.
Read all returned rows and calculate the weighted average of the share price.

mysql - getting only the results with diferences from same table

So I have a single table inside which I have a score system for points. It looks something along this line:
Columns:
ID Name Date Points
1 Peter 2014-07-15 5
2 John 2014-07-15 6
3 Bill 2014-07-15 3
and so on...
Everyday, the new results are being put into the table with the total amount of points acumulated, however in order to be able to get historic values, the results are put into new rows. So on the 2014-07-16, the table will look like this:
ID Name Date Points
1 Peter 2014-07-15 5
2 John 2014-07-15 6
3 Bill 2014-07-15 3
4 Peter 2014-07-16 11
5 John 2014-07-16 12
6 Bill 2014-07-16 3
However sometimes when a player doesn't take part for the whole day and doesn't get any points, he will still be added, but the points will remain the same (here this is shown by the case of Bill).
My question is how to count the number of each type of players (active - Peter and John ie when the points value changes from one date to another and inactive - Bill ie when the points value stays the same).
I have managed to get this query to only select players who do have the same value, but it's giving me the list of players rather than the count. Although I could potentialy be wrong with this query:
SELECT Points, name, COUNT(*)
FROM points
WHERE DATE(Date) = '2014-07-15' OR DATE(Date) = '2014-07-16'
GROUP BY Points
HAVING COUNT(*)>1
I'm not sure how to count the number of rows (could do a bypass trick with PHP getting the number of rows, but interested in SQL only) or how to invert it, to get a count of players who have a different score (again, could get total of rows and then subtract the above number, but not interested in that either - I'd prefer the SQL).
Regards and thanks in advance.
You are pretty close.
If you have at most one row per "player" per "date", you could do something like this:
SELECT SUM(IF(c.cnt_distinct_points<2,1,0)) AS cnt_inactive
, SUM(IF(c.cnt_distinct_points>1,1,0)) AS cnt_active
FROM ( SELECT p.name
, COUNT(DISTINCT p.points) AS cnt_distinct_points
FROM points p
WHERE DATE(p.Date) IN ('2014-07-15','2014-07-16')
GROUP BY p.name
) c
The inline view query (aliased as c) gets a count of the distinct number of "points" values for each player. We need to "group by" name, so we can get a distinct list of players, along with an indication whether the points value was different or not. If all of the non-NULL "points" values for a given player are the same, COUNT(DISTINCT ) will return a value of 1. Otherwise, we'll get a value larger than 1.
The outer query processes that list, collapsing all of the rows into a single row. The "trick" is to use expressions in the SELECT list that return 1 or 0, depending on whether the player is "inactive", and perform a SUM aggregate on that. Do the same thing, but a different expression to return a 1 if the player is "active".
If the count of distinct points for a player is 1, we'll essentially be adding 1 to cnt_inactive. Similarly, of the distinct points for a player is greater than 1, we'll be adding 1 to the cnt_active.
If this doesn't make sense, let me know if you have questions.
NOTE: Ideally, we'd avoid using the DATE() function around the p.Date column reference, so we could enable an appropriate index.
If the Date column is defined as (MySQL datatype) DATE, then the DATE() function is unnecessary. If the Date column is defined as (MySQL datatype) DATETIME or TIMESTAMP, we could use an equivalent predicate:
WHERE p.Date >= '2014-07-15' AND p.Date < '2014-07-16' + INTERVAL 1 DAY
That looks more complicated, but a predicate of that form is sargable (i.e. MySQL can use an index range scan to satisfy it, rather than having to look at every row in the table.)
For performance, we'd probably benefit from an index with leading columns of name and date
... ON points (`name`,`date`)
(MySQL may be able to avoid a "Using filesort" operation for the GROUP BY).
I would solve this problem by looking at the previous number of points and then doing a comparison:
select date(date), count(*) as NumActives;
from (select p.*,
(select p2.points
from points p2
where p2.name = p.name and p2.date < p.date
order by p2.date desc
limit 1
) as prev_points
from points p
) p
where prev_points is NULL or prev_points <> points;
Of course, you can add a where clause to get the count for any particular day.

Need to pull data from mysql by unique userid, max rounds, then sort by another value

A couple months ago I asked a question about something similiar to this, received some help and thought I had the answer. 3 months later I am seeing this didnt work 100% so I need some more help but I can ask the question better now that I understand more.
I have a mysql table with id, userid, rounds, reps, exerciseid
I need to pull a users highest round specific to the exercise I am pulling for. So if the exerciseid was 8 I would need the users top round for that exerciseid but if the user has the same rounds more than once, which happens a lot, then I need to sort that by the reps to give me a true highest performance. Now, after obtaining those results I need to then sort this data set by rounds,reps so if multiple unique users have the same rounds that is then ordered by reps.
Can this be done with pure mysql or am I better off pulling the data and sorting everything with PHP?
SELECT
max(l.rounds) as rounds,
l.reps,l.userid
from leaderboard l
where l.exerciseid = 8
group by l.userid
order by
rounds desc,
reps desc
example of structure
First this is a smaple set
userid exerciseid rounds reps
-- -- --
1 8 23 10
1 8 23 15
1 8 20 10
2 8 28 19
2 8 15 12
3 8 40 29
results I want
userid exerciseid rounds reps
-- -- --
3 8 40 29
2 8 28 19
1 8 23 15
If I understand this correctly, you want to first group by userid and rounds to get the maxreps on a round. Then you want to select the max rounds from this.
Here is one way to express this in MySQL:
select userid, rounds, maxreps
from (SELECT userid, l.rounds, MAX(l.reps) as maxreps
from leaderboard l
where l.exerciseid = 8
group by l.userid, l.rounds
) ur
where exists (select 1 from leaderboard lb where ur.userid = lb.userid and lb.exerciseid = 8 group by lb.userid having max(rounds) = ur.rounds))
order by rounds desc, maxreps desc
how about:
SELECT
max(l.rounds) as rounds,
max(l.reps) as reps,l.userid
from leaderboard l
where l.exerciseid = 8
group by l.userid, l.exerciseid
order by
rounds desc,
reps desc

Categories