Click here to Skip to main content
15,917,608 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have a project where suppose there are 50 hospitals. No any user can rate this hospitals. Now based on number of time voted to one particular hospital I get the average rating of particular hospitals. Now based on average rating I want to give them rankings. This is where I stucked. Because Average ratings get fluctuate every time when any new user vote any hospitals. Every hospitals has six different kind of rating from (10) So they will have total of (60). Base on every single rating (sum) to particular hospital gets divided by number of time that hospital voted * 6 (because 6 types of ratings). This is how I structured my sql Query to get avg rating which is working.


Now how Can I Rank all hospitals with their avg ratings. I just need to understand the logic.

What I have tried:

SQL
SELECT IFNULL((SUM(charges) + SUM(behaviour) + SUM(admission) + SUM(properInformation) + SUM(hygine) + SUM(treatment))/(count(hospitalID) * 6), 0) AverageRating, COUNT(ID) RatingCount FROM ratings WHERE hospitalID = '1111'
Posted
Updated 14-Sep-21 15:12pm
v2

1 solution

You can rank the results by assigning a row number and ordering by the calculated average.

Unfortunately MySQL doesn't have a built-in row number function (yet) but I found a neat trick by OMG Ponies on this link[^]

Demo:
I created a table thus:
SQL
create table myTable
(
  id int not null auto_increment,
  aValue char(30),
  primary key (id)
);

INSERT INTO myTable (aValue) VALUES
    ('dog'),('cat'),('penguin'),
    ('lax'),('whale'),('ostrich');

The data isn't that important but I took care that the values were not in alpha order.
This query
SQL
SELECT t.*, 
       @rownum := @rownum + 1 AS rank
  FROM myTable t, 
       (SELECT @rownum := 0) r
order by aValue desc;
generates these results
id  aValue  rank
5   whale    1  
3   penguin  2 
6   ostrich  3 
4   lax      4 
1   dog      5 
2   cat      6 
but if all I do is change the order
SQL
order by aValue asc;
I get
id  aValue  rank
2   cat      1 
1   dog      2 
4   lax      3 
6   ostrich  4 
3   penguin  5 
5   whale    6 
I.e. the "rank" is dynamic

[EDIT after OP comment]
I think your query needs to look like this:
SQL
SELECT IFNULL((SUM(charges) + SUM(behaviour) + SUM(admission) + SUM(properInformation) + SUM(hygine) + SUM(treatment))/(count(hospitalID) * 6), 0) AverageRating, 
COUNT(ID) RatingCount,
       @rownum := @rownum + 1 AS rank
  FROM ratings t, 
       (SELECT @rownum := 0) r
WHERE hospitalID = '1111'
order by 1 desc

Note - this is untested as I don't have any sample data to work from.

[EDIT 2]
Now that I've seen the sample data, this solution works.
Firstly I had to create a "temporary" table because you have stored numeric data as type varchar. You should never do this - always use the appropriate datatype for the data that will be in the column. Varchar/char should only be used for alphanumeric data (like names for example).
SQL
CREATE TABLE rateTemp
(
  `hospitalID` varchar(100) NOT NULL,
  `AverageRating` DECIMAL(15,2),
  RatingCount INT
);
INSERT INTO rateTemp
SELECT hospitalID, CAST(IFNULL((SUM(charges) + SUM(behaviour) + SUM(admission) + SUM(properInformation) + SUM(hygine) + SUM(treatment))/(count(hospitalID) * 6), 0) AS decimal(15,2)) AverageRating, 
COUNT(ID) RatingCount
FROM ratings t
GROUP BY hospitalID

I can then use the technique I used above to generate the rank of each hospital and join that result back to the original table
SQL
SELECT DISTINCT A.hospitalID, B.AverageRating, B.RatingCount, rank
FROM 
ratings A
INNER JOIN 
  (SELECT @rownum := @rownum + 1 AS rank, hospitalID, AverageRating, RatingCount
    FROM rateTemp t, (SELECT @rownum := 0) r
    ORDER BY AverageRating DESC
) B ON A.hospitalID=B.hospitalID
WHERE A.hospitalID = '446795'

For this example I got the result Rank = 4.
Note - if you don't fix your original table schema then you will have to recreate the rateTemp table each time. If you do fix your table schema then you can probably get rid of rateTemp altogether
 
Share this answer
 
v3
Comments
SuRaj Dedhia 22-May-16 13:20pm    
That is worked but there are some minor flaw in this. I think it just checks first character of any values. Since in my case rating can be anything between 1-10 so If some row has rating 10 then it given last ranking where as if it is 10 then it should be 1st ranking. Others than that all working fine. Please suggest..
CHill60 22-May-16 13:23pm    
Are you storing the rating as an int or as a varchar?
The query is not limiting anything to the first character.
A small sample of your data would help me check this.
SuRaj Dedhia 22-May-16 13:28pm    
I have created table exactly as per your query. Just Put numbers instead of char like this..

INSERT INTO myTable (aValue) VALUES
('8'),('6.3'),('10'),
('5.5'),('3'),('9');

so a value with 10 should display as rank1 but it gets last rank because I think in 10 it takes 1 as lowest value. Other than all values get correct rank
CHill60 22-May-16 13:50pm    
My table was only meant as an example. aValue in my example is a char so the ORDER BY will be based on characters so it would come out as 10,3,5.5,6.3,8,9.
If you want to use my example then change the type of aValue to double.
I'll update my solution with what I think your query will need to look like
SuRaj Dedhia 22-May-16 14:14pm    
So it is basically counting position of row. When I apply where clause it will generate 1 record and rank will be 1 always for any result. I tried your updated code. Unfortunately this couldn't be my solution :(

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900