My SQL - Refer data from another table rows - mysql

I have no idea whether it is possible or not.
I have two tables:
Columns in hospitals Table
hospitalID
Name
AverageRating
Columns in ratings Table
ID
rating1
rating2
rating3
rating4
rating5
rating6
hospitalID
rating1 to rating6 is types of ratings. Now By calculation I am able to get average rating of particular hospital in ratings table from following SELECT Query
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 = '111111'
Above query works for me perfectly but this averageRating I also want to calculate in my hospitals table because I want to ranks hospitals.
Is there any functions in mySQL through which I can calculate average rating to hospitals table by referring ratings table.
Rating Table
Query Output Table

Based on the given table structure, you can try this.
EDIT
SELECT avgratings.*, #curRow := #curRow + 1 AS hospitalRank
FROM (
SELECT (SUM(r.`rating1`)+SUM(r.`rating2`)+SUM(r.`rating3`)+SUM(r.`rating4`)+SUM(r.`rating5`)+SUM(r.`rating6`))/(COUNT(r.`hospitalID`)*6) AS AverageRating, h.hospitalID
FROM hospitals h INNER JOIN ratings r
ON h.`hospitalID`=r.`hospitalID`
WHERE 1 GROUP BY r.`hospitalID`
) avgratings JOIN (SELECT #curRow := 0) rank
ORDER BY avgratings.AverageRating DESC
2nd Query to get rank of a particular hospital.
SELECT tablea.*
FROM (
SELECT avgratings.*, #curRow := #curRow + 1 AS hospitalRank
FROM (
SELECT (SUM(r.`rating1`)+SUM(r.`rating2`)+SUM(r.`rating3`)+SUM(r.`rating4`)+SUM(r.`rating5`)+SUM(r.`rating6`))/(COUNT(r.`hospitalID`)*6) AS AverageRating, h.hospitalID
FROM hospitals h INNER JOIN ratings r
ON h.`hospitalID`=r.`hospitalID`
WHERE 1 GROUP BY r.`hospitalID`
) avgratings JOIN (SELECT #curRow := 0) rank
) tablea
WHERE tablea.hospitalID=1 ORDER BY tablea.AverageRating DESC
Replace 1 in WHERE block with hospitalID.

I am not sure I understand your question...
You get the avarage of a single record with:
charges + behaviour + admission + properInformation + hygine + treatment / 6
You get the total avarage hence with:
avg(charges + behaviour + admission + properInformation + hygine + treatment / 6)
I order to get it per hospital, you'd group by hospital_id:
select
hospitalid,
avg(charges + behaviour + admission + properinformation + hygine + treatment / 6) as avr,
count(*) as rating_count
from ratings
group by hospitalid
order by 2 desc;
You can select the hospital data (e.g. the hospital name) along by joining the hospital table. E.g.
select
h.hospitalid,
h.name,
avg(r.charges + r.behaviour + r.admission +
r.properinformation + r.hygine + r.treatment / 6) as average_rating,
count(*) as rating_count
from hospitals h
left join ratings r on r.hospitalid = h.hospitalid
group by h.hospitalid
order by average_rating desc;

Related

MySQL - Percentile calculation and update it in other column in the same table

I have a table in MySQL (phpMYAdmin) with the following columns
I am trying to determine the percentile for each row and update that value in the G1Ptile column. G1Ptile column is the percentile calculation based on G1%. I am using the following based on John Woo's answer given here
SELECT `G1%`,
(1-ranks/totals)*100 Percentile FROM (
SELECT distinct `G1%`,
#rank:=#rank + 1 ranks,
(SELECT COUNT(*) FROM PCount) totals
FROM PCount a,
(SELECT #rank:=0) s
ORDER BY `G1%` DESC ) s;
and get the following output
The output is in a select statement, I want to be able to update it to the G1Ptile column in my table, however I am unable to update it using
UPDATE `PCount` SET `G1Ptile`= --(All of the select query mentioned above)
Can you please help with modifying the query/suggest an alternative so that I can use the percentile values obtained using the above query and update it into G1Ptile in the same table. One more problem I have is that there are two 20% values in G1%, however the percentile assigned to one is 20 and other is 30. I want both of them to be 20 and the next row in the series to be 30.
I would write your calculation as:
SELECT `G1%`,
(1 - ranks / totals) * 100 as Percentile
FROM (SELECT `G1%`,
(#rank := #rank + 1) ranks,
(SELECT COUNT(*) FROM PCount) as totals
FROM (SELECT DISTINCT `G1%`
FROM PCount
ORDER BY `G1%` DESC
) p CROSS JOIN
(SELECT COUNT(*) as totals, #rank := 0
FROM Pcount
) params
) p;
I made certain changes more consistent with how MySQL processes variables. In particular, the SELECT DISTINCT and ORDER BY are in a subquery. This is necessary in more recent versions of MySQL (although in the most recent you can use window functions).
This can now be incorporated into an update using JOIN:
UPDATE PCount p JOIN
(SELECT `G1%`,
(1 - ranks / totals) * 100 as Percentile
FROM (SELECT `G1%`,
(#rank := #rank + 1) ranks,
(SELECT COUNT(*) FROM PCount) as totals
FROM (SELECT DISTINCT `G1%`
FROM PCount
ORDER BY `G1%` DESC
) p CROSS JOIN
(SELECT COUNT(*) as totals, #rank := 0
FROM Pcount
) params
) pp
) pp
ON pp.`G1%` = p.`G1%`
SET p.G1Ptile = pp.percentile;

Mysql query get SUM() specific row?

Is it possible to get specific row in query using like SUM?
Example:
id tickets
1 10 1-10 10=10
2 35 11-45 10+35=45
3 45 46-90 10+35+45=90
4 110 91-200 10+35+45+110=200
Total: 200 tickets(In SUM), I need to get row ID who have ticket with number like 23(Output would be ID: 2, because ID: 2 contains 11-45tickets in SUM)
You can do it by defining a local variable into your select query (in form clause), e.g.:
select id, #total := #total + tickets as seats
from test, (select #total := 0) t
Here is the SQL Fiddle.
You seem to want the row where "23" fits in. I think this does the trick:
select t.*
from (select t.*, (#total := #total + tickets) as running_total
from t cross join
(select #total := 0) params
order by id
) t
where 23 > running_total - tickets and 23 <= running_total;
SELECT
d.id
,d.tickets
,CONCAT(
TRIM(CAST(d.RunningTotal - d.tickets + 1 AS CHAR(10)))
,'-'
,TRIM(CAST(d.RunningTotal AS CHAR(10)))
) as TicketRange
,d.RunningTotal
FROM
(
SELECT
id
,tickets
,#total := #total + tickets as RunningTotal
FROM
test
CROSS JOIN (select #total := 0) var
ORDER BY
id
) d
This is similar to Darshan's answer but there are a few key differences:
You shouldn't use implicit join syntax, explicit join has more functionality in the long run and has been a standard for more than 20 years
ORDER BY will make a huge difference on your running total when calculated with a variable! if you change the order it will calculate differently so you need to consider how you want to do the running total, by date? by id? by??? and make sure you put it in the query.
finally I actually calculated the range as well.
And here is how you can do it without using variables:
SELECT
d.id
,d.tickets
,CONCAT(
TRIM(d.LowRange)
,'-'
,TRIM(
CAST(RunningTotal AS CHAR(10))
)
) as TicketRange
,d.RunningTotal
FROM
(
SELECT
t.id
,t.tickets
,CAST(COALESCE(SUM(t2.tickets),0) + 1 AS CHAR(10)) as LowRange
,t.tickets + COALESCE(SUM(t2.tickets),0) as RunningTotal
FROM
test t
LEFT JOIN test t2
ON t.id > t2. id
GROUP BY
t.id
,t.tickets
) d

Partition data in Percentile range and assign different value for different Range

I have table structure as shown in below
Temp
Customer_id | sum
Now I have to create view with extra column customer_type and assign value 1 if customer lies in top 10% customer (with descending order of sum,also total number of customer may vary) and 2 if customer lies between 10%-20%, 3 if customer lies between 20%-60% and 4 if customer lies between 60%-100%. How can I do this?
I just able to extract top 10% and between 10% - 20% data but couldn't able to assign value as (source)
SELECT * FROM temp WHERE sum >= (SELECT sum FROM temp t1
WHERE(SELECT count(*) FROM temp t2 WHERE t2.sum >= t1.sum) <=
(SELECT 0.1 * count(*) FROM temp));
and (not efficient just enhance above code)
select * from temp t1
where (select count(*) from temp t2 where t2.sum>=t2.sum)
>= (select 0.1 * count(*) from temp) and (select count(*) from temp t2 where t2.sum>=t1.sum)
<= (select 0.2 * count(*) from temp);
Sample data are available at sqlfiddle.com
This should help you. You need to get row number for sum and total number of rows. I'm sure you can figure out the rest easily.
SELECT
*,
#curRow := #curRow + 1 AS row_number,
(#curRow2 := #curRow2 + 1) / c as pct_row
FROM
temp t
JOIN (SELECT #curRow := 0) r
JOIN (SELECT #curRow2 := 0) r2
join (select count(*) c from temp) s
order by
sum desc
This is based on this answer
I had solve this as like this. Thanks for #twn08 for his answer which guide me upto this.
select customer_id,sum,case
when pct_row<=0.10 then 1
when pct_row>0.10 and pct_row<=0.20 then 2
when pct_row>0.20 and pct_row<=0.60 then 3
when pct_row>0.60 then 4
end as customer_label from (
select customer_id,sum,(#curRow := #curRow+1)/c as pct_row
from temp t
jOIN (SELECT #curRow := 0) r
JOIN (SELECT #curRow2 := 0) r2
join (select count(*) c from temp) s
order by sum desc) p;
I don't know whether this is efficient method or not but work fine for small data set.

Can I do a mysql command to filter and delete duplicated entry

I have table as linkage with below values
++++++++++++++++++++++++++
+ company_id + industry +
++++++++++++++++++++++++++
+ 1 + a +
+ 1 + b +
+ 2 + a +
+ 2 + c +
+ 3 + a +
+ 4 + c +
+ 5 + a +
++++++++++++++++++++++++++
Is there a way that i can group my industry to get the top count sort by desc order example.
a = count 4
c = count 2
b = count 1
then delete duplicated industry leaving only the industry that has the higher count for each company_id.
Edit 1
This edit is based on OP comment I wish to only have the industry with the highest count, and deleting the rest of the entry for the same company_id. say for company_id 1, we will delete the second row, for company_id 2 we will delete the forth row.
Below is what I have.
++++++++++++++++++++++++++
+ company_id + industry +
++++++++++++++++++++++++++
+ 1 + a +
+ 1 + b +
+ 1 + c +
+ 2 + a +
+ 2 + c +
+ 3 + a +
+ 4 + c +
+ 5 + a +
++++++++++++++++++++++++++
as we see in column industry, a has max count, I would like to keep this entry per duplicated company_id and remove rest all enteries.
Consider company_id=1. I would need to remove second and third row.
Consider company_id=2. I would need to remove fifth row.
For id=3,4,5 nothing will happen as those are not duplicated.
So final data that should be there in my table is
++++++++++++++++++++++++++
+ company_id + industry +
++++++++++++++++++++++++++
+ 1 + a +
+ 2 + a +
+ 3 + a +
+ 4 + c +
+ 5 + a +
++++++++++++++++++++++++++
select t6.company_id,t6.industry from
(select t5.company_id,t5.industry,
row_number() over (partition by t5.company_id order by t5.company_id) rn
from
(select t3.company_id,t4.industry from
(select t2.company_id,max(t2.count) count from(
select m.company_id,m.industry,t1.count from linkage m
join
(select n.industry,count(n.industry) count from linkage n
group by n.industry
order by count desc)t1
on m.industry = t1.industry
order by m.company_id)t2
group by t2.company_id
order by t2.company_id)t3
join
(
select m.company_id,m.industry,t1.count from linkage m
join
(select n.industry,count(n.industry) count from linkage n
group by n.industry
order by count desc)t1
on m.industry = t1.industry
order by m.company_id)t4
on t3.company_id = t4.company_id
and t3.count = t4.count)t5
)t6
where t6.rn = '1'
How about this?
SELECT industry, count(industry) as "total"
FROM linkage
GROUP BY industry
ORDER BY total DESC
Demo at sqlfiddle
Edit 1
Can you take at look at below question.
how can I delete duplicate records from my database
I think that is what you are looking for.
select n.industry,count(n.industry) count from linkage n
group by n.industry
order by count desc
select t3.company_id,t4.industry from
(select t2.company_id,max(t2.count) count from(
select m.company_id,m.industry,t1.count from linkage m
join
(select n.industry,count(n.industry) count from linkage n
group by n.industry
order by count desc)t1
on m.industry = t1.industry
order by m.company_id)t2
group by t2.company_id
order by t2.company_id)t3
join
(
select m.company_id,m.industry,t1.count from linkage m
join
(select n.industry,count(n.industry) count from linkage n
group by n.industry
order by count desc)t1
on m.industry = t1.industry
order by m.company_id)t4
on t3.company_id = t4.company_id
and t3.count = t4.count
Demo at sqlfiddle

How to Get cumulative totals mysql

I have a table where I keep information about financial returns. The columns includes receipts, repairs, service_amount, tyres, fuel, salaries_allowances, others.
I would like to get the cumulative net return like:
Date Receipts repairs service amount Total costs net Return
2012-01-10 0.00 120,000.00 0.00 120,000.00 120,000.00
2012-01-12 60,000.00 0.00 0.00 60,000.00 60,000.00
I am currently using this query:
SELECT
a.consignment_date, a.receipts, a.service_amount, a.repairs, a.tyres,
a.salaries_allowances, a.clearing_fee, a.others,
a.service_amount + a.repairs + a.tyres + a.salaries_allowances + a.clearing_fee + a.others as total_costs,
(b.receipts -(a.service_amount + a.repairs + a.tyres + a.salaries_allowances + a.clearing_fee + a.others)) as netreturn
FROM
vw_local_freight a CROSS JOIN vw_local_freight b
WHERE
a.consignment_date >= b.consignment_date AND a.vehicle_no='123X'
GROUP BY a.consignment_date
I would look at a query like
SELECT
consignment_date.*,
consignment_date.credits - consignment_date.costs AS totalCosts,
(#runningTotal := #runningTotal + consignment_date.credits - consignment_date.costs) AS netReturn
FROM (
SELECT
consignment_date,
SUM(receipts) AS credits
SUM(service_amount + repairs + tyres + salaries_allowances + clearing_fee + others) AS costs
FROM vw_local_freight
WHERE vehicle_no = '123x'
GROUP BY consignment_date
) AS a, (SELECT #runningTotal := 0) AS b
The subquery tallies up your costs and credits, then the outer query performs your running total. If you need individual column sums within the inner join then they can be added in easily enough.
try this:
SET #runtot:=0;
SELECT
q1.d,
q1.c,
(#runtot := #runtot + q1.c) AS rt
FROM
(SELECT
DAYOFYEAR(date) AS d,
COUNT(*) AS c
FROM orders
WHERE hasPaid > 0
GROUP BY d
ORDER BY d) AS q1
Ok, I'm basing my answer on your query, rather than on your expected table result:
SELECT *, receipts - total_costs as NetReturn FROM (
SELECT a.consignment_date, sum(a.receipts) receipts, sum(a.service_amount),
sum(a.repairs), sum(a.tyres), sum(a.salaries_allowances),
sum(a.clearing_fee), sum(a.others), sum(a.service_amount + a.repairs
+ a.tyres + a.salaries_allowances + a.clearing_fee + a.others) as total_costs
FROM vw_local_freight a
WHERE a.vehicle_no = '123X'
GROUP BY a.consignment_date
) S