Mysql query 5 cheapest cars, multiple makes, from single table - mysql

I have a database of 750 vehicles, I would like to run a query where I select no more than 5 of cheapest vehicles for each make & model and include those in my results.
My table fields are fldYear, fldMake, fldModel, fldRetail etc.
For example I would like the output to include the 5 cheapest Dodge 200 vehicles from 25 in total, the 5 cheapest Honda Accords from 30 in total, the 5 cheapest Jeep Cherokees from 10 in total, and if there only 2 Volkswagon Jettas, to include them as well. In the above example my output would have a total of 17 records.
I have played around with Sorts and Group By but I can't seem to get the desired output.

Just use variables:
SELECT *
FROM (
SELECT *,
#row := if(fldMake = #make,
#row := #row + 1,
if(fldMake := #make, 1, 1)
) as row
FROM yourCars
CROSS JOIN ( SELECT #make := '', #row:=0 ) as vars
ORDER BY fldMake, fldRetail ASC
) as T
WHERE T.row <= 5

I think you should retrieve 5 cheapest vehicle from one brand and put it in array or object. Same for other brands and after retrieving all the required data you can merge them in new array.

Related

SQL Sort By Index sum from Multiple Results By Adding Index corresponding to the same key

I am having difficulty sorting results of multiple queries. The queries I'm running return a sorted list with zipcode as the key. So, for example, 1 query will return sorted zipcodes where crime rate is low, with lowest zipcode having a 1 as its index, then a query that returns zipcodes where average salary is over 100k or less with closest to 100k being index of 1.
Say I have 6 or more similar queries. How can I then sort zipcodes by sum of indices from all queries?
Example queries im running :
SELECT DISTINCT s1.Zip_Code, s1.Median_Value
FROM NJ_Housing_Expenses s1, NJ_Housing_Expenses s2
WHERE s1.Median_Value < 100000 AND s1.Zip_Code NOT IN (
SELECT Zip_Code
FROM NJ_Housing_Expenses
WHERE Median_Value = 0
)
ORDER BY Median_Value DESC
and
SELECT City, (((Violent_Crime*4) + Property_Crime)/Population) as CrimeSum
From NJ_Crime_Statistics
where Date = 2016
Group By City
Order by CrimeSum ASC
OUTPUT
1 08754
2 08234
3 07332
4 09563
then
1 08754
2 07332
3 09563
4 08234
Then is sorted by adding index
1 08754 (2)
2 07332 (5)
3 08234 (6)
4 09563 (7)
Sounds like you want to "number" the rows in each query. We could use a MySQL user-defined variable to do that.
We can wrap a suitable query in parens, and reference it as an inline view (in place of a table). As a demonstration.
SELECT q1.Zip_code
, #q1_rn := #q1_rn + 1 AS rn
FROM ( SELECT #q1_rn := 0 ) i
CROSS
JOIN (
-- source query here as inline view
SELECT s1.Zip_Code
, ...
FROM ...
ORDER BY Median_Value DESC
) q1
ORDER BY q1.Median_Value DESC
We can do the same thing for another query, but use a different user-defined variable
SELECT q2.Zip_code
, #q2_rn := #q2_rn + 1 AS rn
FROM ( SELECT #q2_rn := 0 ) i
CROSS
JOIN (
-- inline view query here
) q2
ORDER BY q2.CrimeSum ASC
We can combine the results of those queries with a UNION ALL set operator, and reference that whole thing as an inline view,
SELECT t.Zip_code
, SUM(t.rn) AS tot_rn
FROM (
(
-- first query from above goes here
)
UNION ALL
(
-- second query from above goes here
)
UNION ALL
(
-- third query
)
UNION ALL
(
-- fourth query
)
) t
GROUP BY t.Zip_code
ORDER BY tot_rn ASC
Add a GROUP BY to collapse all of the rows with the same Zip_Code (the first column returned by each of the source queries... each query should return exactly two columns... Zip_code and rn.
We use a SUM() aggregate to total up the values of rn, giving a total for each Zip_Code.

Cumulative sum query on foreign key

I want to write a query for cumulative sum in MYSQL. I have a foreign key in my table and I want to add their hours as a cumulative sum.
Table 1
id(not primary key) Hours
1 4
2 4
1 5
I have tried this query
select spent_hours := spent_hours + hours as spent
from time
join (select spent_hours := 0) s
I am getting this
id(not primary key) hours spent
1 4 4
2 4 8
1 5 13
But I want this result:
id(not primary key) Hours spent
1 4 4
2 4 4
1 5 9
Since you have an autoincrement field (let's assume for this case its called record_id) you can use this little trick to achieve what you want:
SELECT Main.id, Main.spentHours,
(
SELECT SUM(spentHours)
FROM Table1 WHERE Table1.id = Main.id
AND Table1.record_id >= Main.record_id
) as totalSpentHours
FROM Table1 Main
ORDER BY Main.record_id ASC
This will fetch the id, current spent hours, along using a subselect, all hours from the current ID and above for that user.
You need additional an variable to keep track of the cumulative sum within each id:
select t.id, t.hours,
(#h := if(#i = id, #h + spent_hours,
if(#i := id, spent_hours, spent_hours)
)
) as spent
from time cross join
(select #h := 0, #i := 0) params
order by id, ??;
Note: you need an additional column to specify the order for the cumulative sum (indicated by ?? in the order by clause. Remember that SQL tables represent unordered sets, so you need a column to explicitly represent ordering.

Get N amount of results per category and filter every third result by a row

I extraced some data of my tables to help you reproduce my problem.
The SQL is here (The SQL is adjusted to my current problem, so I didn't include all columns, or all data, because it's not needed)
http://tzfrs.de/dev/test.sql
Now, what I'm doing is the following. I want to get 6 pois per category. This works with the following query
SELECT x.id, x.fsqPoi, x.name, cpc.catName, cpc.className
FROM (
SELECT bp.id, bp.categoryId, bp.fsqPoi, bp.name,
CASE WHEN bp.categoryId = #type
THEN #rownum := #rownum + 1
ELSE #rownum := 1
END AS rank,
#type := bp.categoryId FROM (
select * from pois WHERE cityId = "25" order by id
) bp JOIN (
SELECT #rownum := 0, #type := NULL
) r ORDER BY categoryId ) x INNER JOIN poi_categories cpc ON cpc.id = x.categoryId
WHERE x.rank <= 6 ORDER BY x.categoryId
This returns me 6 pois for every category from the poi table. You can adjust the number of pois per category by defining the number at WHERE x.rank <= XXX.
The problem I'm currently stuck with is the following.
As you can see, I have the column fsqPoi which indicates if the POI has been gathered from Foursquare or not.
I want, that, every first, fourth and seventh POI MUST be a POI from Foursquare. POI 2,3,5,6,8 and 9 can be random, meaning, they can be from Foursquare but don't have to.
This is where I'm stuck. I don't know how to adjust my query to make this work, and I don't know if that does even work. I would greatly appreciate if you could help me out there. Muchas Gracias!

Sum Top 10 Values

I’ve searched and I know this has been asked before but I am struggling to get my head around what I can / can’t do.
My cycling club records race results each time a rider has entered a race. Each result is awarded points - 50 for 1st, 49 for 2nd etc.
So the table looks like
resultid(pk) | riderid(fk) | leaguepts
1 1 50
2 2 49
3 3 48
4 1 50
5 2 42
6 3 50
7 4 30
...etc
I am trying to extract the sum of top 10 points awarded for each riderid from the results table.
(the actual database is a bit more complicated with a table for rider name / rider id and also a race table so we can display the results of each race etc but I just want to get the basic league table query working first of all)
So I want to extract the sum of the top 10 best scores for each rider. Then display each riders score, in a descending league table.
So far I’ve only had success using UNION ALL e.g.
SELECT sum(points) AS pts from
(
SELECT points from `results`
WHERE riderid = 1
ORDER BY points DESC
LIMIT 10
) as riderpts
UNION ALL
SELECT sum(points) AS pts from
(
SELECT points from `results`
WHERE riderid = 2
ORDER BY points DESC
LIMIT 10
) as riderpts
ORDER BY pts DESC
But there could be up to 90-odd riders who have registered at least one score so this query could get very big.
I found this which looks like it should work for me but doesn't. Sum top 5 values in MySQL I changed the column names for my table but it seems to sum all results, not the top 10 for each rider.
Alternatively I could just issue a query for each rider id. Not good I guess?
Subquerying is a problem because I can't limit on the inner query?
Run a job (manual or cron) to update the league table periodically and just display the table results?
Edit (not sure if this is the correct etiquette or I should start a new thread?). Gordon answered the question below but in the meantime I tried to work this out for myself using one of the links below. I could get results that returned the top 10 scores for each rider with the query below
set #riderid = '';
set #riderrow = 1;
select riderid, leaguepts, row_number
from
(
select
riderid,
leaguepts,
#riderrow := if(#riderid = riderid, #riderrow + 1, 1) as row_number,
#riderid := riderid as dummy
from wp_tt_results order by riderid, leaguepts desc
) as x where x.row_number <= 10;
BUT I can't see what I would need to do next to get the sum of top 10 results per riderid?
In MySQL, the easiest way to do this is probably to use variables:
SELECT riderid, sum(points)
FROM (SELECT r.*,
(#rn := if(#r = riderid, #rn + 1,
if(#r := riderid, 1, 1)
)
) as seqnum
FROM results r CROSS JOIN
(SELECT #r := 0, #rn := 0) as wnw
ORDER BY riderid, points DESC
) r
WHERE seqnum <= 10
GROUP BY riderid;

Best 28 result into the sum

I have the following QUERY and I need only the sum of the best 28 results
SELECT id_person, sum(points)
FROM ranking
WHERE id_open>=847 and id_club=2 and id_person!='91'
GROUP BY id_person
ORDER BY sum(points) desc, id_ranking
Each player (id_person), in this serie (id_open=847 or more), in this club (id_club=2) can play about 56 games, but only 28 best result counts for ranking, in other words, I'll despise 28 worst results.
** EDITED QUERY ** (id_ranking isn't necessary in ORDER BY)
SELECT id_person, sum(points)
FROM ranking
WHERE id_open>=847 and id_club=2 and id_person!='91'
GROUP BY id_person
ORDER BY sum(points) desc
If I am understanding correctly...
Your goal: Display players (i.e. id_person) in DESC order based on how many points that person makes in his/her best 28 games.
Here is a query that potentially does that:
SELECT id_person, sum(points) as s
FROM (
SELECT id_person,
points,
#rownum := if(#person = id_person, #rownum + 1, 1) as pointRank,
#person := id_person as dummy
FROM (SELECT id_person, points
FROM ranking
WHERE id_open >= 847 and id_club = 2 and id_person != '91'
ORDER BY id_person, points DESC
) as q1,
(SELECT #rownum := 0) as r,
(SELECT #person := '') as s
) as q2
WHERE pointRank <= 28
GROUP BY id_person
ORDER BY s DESC;
SQL Fiddle (Note: leaves out q1's WHERE clause for convenience)
Subquery q1 explanation:
Filters out rows based on id_open, id_club, and id_person.
Then, orders based on id_person (implicitly ASC) and points (explicitly DESC).
Finally, selects the id_person and points fields.
Note: MySQL Group By's are a little special - aggregates will work, but if selecting non-aggregates, a random row will be selected for the group by, not all rows (MYSQL-Group-By-returns-only-first-row)
Subquery q2 explanation:
Adds in rownum and person variables to keep track of ranking of game. (generate-column-containing-record-index-in-table)
Needs to use the (SELECT #rownum := 0) as r and (SELECT #person := '') as s to set the variables. (These variables could be set outside too.)
if(#person := id_person, #rownum + 1, 1) is necessary to reset the ranking of games per person.
Note: Important to initialize the person variable to an empty string, as opposed to 0. Not too sure why, but if you do not, then it will not reset the rownum variable correctly.
Overall query explanation:
All row numbers (i.e. pointRank) less than or equal to 28 (basically, the 28 best point scores per id_person) are kept.
After this filtering, each id_person will be grouped again.
Finally, the top 28 games' points will be summed up and labeled as s, and these pairs (id_person,s) will be ordered from highest to lowest.
Here is another StackOverflow question with a good article link inside (highly recommended read): (limit-within-group)
Note: I cannot guarantee this will work though, since I do not know what your table looks like. That information would help.