Finding the id whose average sum is maximum compared to other id - mysql

I have a MySQL table named "Rating" which contains (id, rateable_id, rating, user_id) columns. rateable_id is the id of a record which is rated and rated score is stored in rating (star rating). All I want to do is to find particular rateable_id (grouped by) whose sum average is maximum among other rateable_id.
In the above sample table , i should get rateable_id = 26 because its rating is max ((3+3)/2) = 3 as compared to other rateable_id.
raw sql or eloquent any preferred.
Edit: Sorry to mention but i have done roughly in not standard way Anyway it returns the answer but i am looking using nested select answer. averageRating is willvincent package for counting avg sum of rating. $popular_post returns the id whose average rating sum maximum.
$posts = "App\Opportunity"::all(); //where(createdate < 1month)
$i=11;
$cr=0;
$pr=0;
$mi = 0; //max index
$maxR=0; //max rating value
for($i=0; $i< count($posts); $i++)
{
$cr = $posts[$i]->averageRating; //current rating
if($cr)<br>
{
if($cr > $maxR)
{
$maxR = $cr;
$mi = $i;
}
}
else
{
// echo "skip<br>";
}
}
$popular_post = ($posts[$mi]->id);

You are going to need 2 selects:
SELECT MAX(rating) rating, rateable_id FROM (
SELECT AVG(rating) rating, rateable_id FROM table GROUP BY reateble_id
) GROUP BY rateable_id ORDER BY rating LIMIT 1

I think this will help you little bit.
$ratings = Rating::all()->groupBy('rateable_id');
$topList = [];
foreach($ratings as $key => $value){
$topList[$key] = ($value->sum('rating')) / count($value);
}
arsort($topList); //sort the array by top values
$max_rateable_id = key($topList); //key of first item of the array
$max_rating = reset($topList); //value of first item of the array
$both = [$max_rateable_id => $max_rating]; //key and value of the first item of the array

Related

MySQL SUM CASE returning incorrect calculated amount

Apologies for the confusing title
I have a table 'trainees' which lists booked places on a sailing trip
I then have a berth options table which lists among other things lists whether the berth is booked individually or as a cabin.
I am trying to get the total number of booked berths, however;
if the voption_pricedIndividually is 1 then the number of places added to the total should be 1.
If the voption_pricedIndividually is 0 then regardless of the number of 'trainees' booked the number of places added to the total should be the maximum number of people permitted in the cabin. voption_berthsAvailable. So in this case 3.
In the images above, there are:
2x trainees booked in berth 1 and
3x trainees booked in berth 5.
I need a total number of trainees booked, however if they are in a cabin, regardless of the number booked, it needs to return the maximum occupancy.
So in this case we have 3x individual bookings and then 3x more from the maximum occupancy as set in voption_berthsAvailable.
The expected outcome is 6.
After some great help by #Luuk I'm getting closer but the below is multiplying the sum by the number of rows (30 instead of 6)
SELECT voyage_name, voyage_startDate, voyage_id, session_name,
SUM(test.bookings) AS berthTotals
FROM voyages
LEFT JOIN voyagesessions ON voyagesessions.session_voyageID = voyages.voyage_id
LEFT JOIN trainees ON trainees.trainee_voyageID = voyages.voyage_id
LEFT JOIN vesseloptions ON vesseloptions.voption_id = trainees.trainee_berthID
LEFT JOIN
(SELECT SUM(bookings) as bookings, trainee_voyageID, trainee_sessionID FROM (
SELECT voption_pricedIndividually, trainee_voyageID, trainee_sessionID,
CASE WHEN voption_pricedIndividually = 0
THEN
MIN(CASE WHEN voption_pricedIndividually = 1
THEN 1
ELSE voption_berthsAvailable END)
ELSE
SUM(CASE WHEN voption_pricedIndividually = 1
THEN 1
ELSE voption_berthsAvailable END)
END as bookings
FROM trainees
LEFT JOIN vesseloptions ON vesseloptions.voption_id = trainees.trainee_berthID
LEFT JOIN voyagesessions ON voyagesessions.session_id = trainees.trainee_sessionID
GROUP BY voption_pricedIndividually, CASE WHEN voption_pricedIndividually <> 0 THEN voption_id END
) x ) as test ON test.trainee_voyageID = voyages.voyage_id
GROUP BY voyage_name, session_name, voyages.voyage_startDate, voyage_id
ORDER BY voyage_startDate, voyage_name
Getting close but now the math is not working.
The query is nearly there but it is returning the correct number but multiplying it by the number of records. Should be 6 not 30
Structures can be found in the DBFIDDLE https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=2d14e5048e2667551fc2d9c6d6010166
Ok, so I may have cheeted a little as this isn't in a complete query and I used some PHP but.....
**GetVoaygesBySession**
SELECT * FROM voyagesessions
LEFT JOIN voyages ON voyages.voyage_id = voyagesessions.session_voyageID
WHERE session_deleted != 1
**getTraineesByVoyageAndSession**
SELECT * FROM trainees
LEFT JOIN vesseloptions ON vesseloptions.voption_id = trainees.trainee_berthID
WHERE trainee_voyageID = :voyage
AND trainee_sessionID = :session
AND trainee_status != 6
Then I created multiple foreach loops to run through each result and build an array I can use totally the berth counts as it loops through.
I basically had it add to $i when it was a individual berth on each loop and just overwrite the same number $s with the total in the berth on each loop for the cabins.
$i = 0;
$c = 0;
$voyageD = array();
$sessionsandvoyages = $this->voyageModel->getVoyagesBySession();
foreach ($sessionsandvoyages as $trip) {
$trainees = $this->traineeModel->getTraineesByVoyageAndSession($trip->voyage_id, $trip->session_id);
foreach ($trainees as $trainee) {
if ($trainee->voption_pricedIndividually == 1) {
$i++;
} else {
$c = $trainee->voption_berthsAvailable;
}
}
$total = $i + $c;
$voyageD[] = array(
'voyage_name' => $trip->voyage_name,
'voyage_startDate' => $trip->voyage_startDate,
'voyage_id' => $trip->voyage_id,
'session_name' => $trip->session_name,
'berthBookings' => $total
);
$total = 0;
$i = 0;
$c = 0;
}
I realise this is probably not the most efficient way of doing it but at the moment it is the only way I can get it to work

database query to get lowest price based on last crawel date

I would like to get lowest price of product based on last crawled dates by various resellers. My current function is very basic, it gets me lowest price from table without considering reseller ids and crawled timestamps.
I've rough idea that we can SELECT * FROM "custom_data_table" and process the data using php. Please have a look at attachment for further clarification.
function get_lowest_price($table_id) {
global $wpdb;
$table_prices = $wpdb->get_results(
$wpdb->prepare(
"SELECT price FROM `custom_data_table` WHERE tableid= %d"
,$table_id)
);
if (!empty($table_prices) && $table_prices !== NULL)
return rtrim(min($table_prices)->price, '00');
}
The right query here is:
SELECT price
FROM custom_data_name cdn, (
SELECT MAX(crawled) AS maxCrawled, resellerid
FROM custom_data_name
GROUP BY resellerid
) cdnFiltered
WHERE cdn.crawled = cdnFiltered.maxCrawled AND
cdn.resellerid = cdnFiltered.resellerid AND
tableid = %d;
Try this:
SELECT B.price
FROM (SELECT resellerid, MAX(crawled) max_crawled
FROM custom_data_table
GROUP BY resellerid) A
JOIN custom_data_table B
ON A.resellerid=B.resellerid AND A.max_crawled=B.crawled;
Maybe use ORDER BY crawled and LIMIT 1

How return only value change from a mysql query without using php?

I have 2 mysql tables with 500.000 items
first with items price, items id, and ticket number
second with ticket_number, date of sales and total_price of ticket
by now i use this query
SELECT items.pri,ticket.date,items.crd,items.plu
FROM items ,ticket
WHERE
(items.crd = 25 OR items.crd = 30) AND items.SeqNbr = ticket.SeqNbr
then in php:
$val_1 = array();
$price1 = 0;
while($row = mysql_fetch_array($query))
{
if($row['crd'] == 25)
{
$prix = $row['pri'];
if($prix != $price1)
{
$val_1[] = array( (int)$row['date']*1000,(float)$row['pri']);
$price1 = $prix;
}
}
}
return:
[[1388552879000,1.519],[1389136505000,1.498],[1392420222000,1.514],[1394667334000,1.499],[1395373887000,1.478],[1395963467000,1.499],[1396649284000,1.52],[1397513210000,1.542],[1398384245000,1.556],[1399347974000,1.536],[1400910286000,1.553],[1403216692000,1.58],[1405029076000,1.563]]
goal is obtain an array with price change and date to build a charts of price fluctuation.
but with more than 500.000 records this is extremly slow (15 sec)
is there any possibilities to build mysql query that return the same array ?
Thanks
First you need to check where is the bottleneck, on the query or on the loop.
If it is on the query, check if you have the right index. If not, try adding index for the fields items.crd, items.SeqNbr and ticket.SeqNbr.

mysql select count(column) where sum(column) > value

I'm trying to query $wpdb to get back an int value of the number of users in a custom table who have recorded a number of hours volunteer work above a set target - these hours need to have been moderated ( value set to = 1 ) - I have this so far:
EDIT - updated to use consistent {} around php variables in query --
$target = get_post_meta($post->ID, 'target', true) ? (int)get_post_meta($post->ID, 'target', true) : 100;
$awards = $wpdb->get_var("
SELECT user_id
FROM {$this->options['rewards_logging']}
WHERE moderated = 1 AND reward_id = {$post->ID}
GROUP BY user_id
HAVING sum(hours) > {$target}
");
Which returns the correct value of '0' if none of the hours are approved ( moderated = 0 ), however as soon as one of those users hours are approved, this query returns the count of all the users who have logged more than the target hours ( whether they have been approved or not ).
Any pointers!
Cheers
Ray
Seems I was trying to get back a single variable using $wpdb->get_var, when I really needed the whole result set:
$awards = $wpdb->get_results("
SELECT user_id
FROM {$this->options['rewards_logging']}
WHERE moderated = 1 AND reward_id = {$post->ID}
GROUP BY user_id
HAVING sum(hours) > {$target}
");
Then I can check over the data and display a result - etc...:
if ( count($awards) > 0 ) {
#var_dump($awards);
echo '<span class="awards-notice">'.count($awards).'</span>';
} else {
echo '-';
}

How to include zero when counting with a MySQL GROUP BY expression

I'd like to count the number events that occur on each day over the last month, but also include a count of zero when no events are found. Is that possible?
Here's what I'm starting from...
SELECT COUNT(*) AS count,
DATE(usage_time_local) AS d
FROM usages
WHERE user_id=136
AND DATE(usage_time_local) >= DATE('2011-04-24')
AND DATE(usage_time_local) <= DATE('2011-05-24')
GROUP BY DATE(usage_time_local);
UPDATE: Given the answer, I implemented a code solution by initializing a loop and then filling in the details.
$dailyCount = array();
for( $i=1; $i<=30; $i++ ) {
$day = date('Y-m-d',(time()-($i*24*60*60)));
$dailyCount[$day] = 0;
}
foreach( $statement as $row ) {
$dailyCount[$row['d']] = $row['count'];
}
You can't do this with standard SQL queries - you'd be trying to group on a date(s) that doesn't exist in the table.
Standard workaround is to make a temporary table that contains the date range in sequential order with no gaps, join that against your table and do the count/aggregate as usual.