I have a MYSQL table of sports team results. Each event or match is stored with a for and against goals scored value. What I would like to do is retrieve an ordered list matches order by goals conceeded (ascending).
It seems simple enough until the team in question is the away team:
in which case we are looking at goals at for.
When the team in question is the home team we are looking at goals 'against'.
I can written the following query:
(SELECT * FROM `matches`,`teams`,`outcomes`
WHERE `home_team_id`=11 AND `matches`.away_team_id=`teams`.team_id
AND `matches`.score_id=`outcomes`.outcome_id
ORDER BY `against`,`date` DESC LIMIT 0,20)
UNION
(SELECT * FROM `matches`,`teams`,`outcomes`
WHERE `away_team_id`=11 AND `matches`.home_team_id=`teams`.team_id
AND `matches`.score_id=`outcomes`.outcome_id
ORDER BY `for`,`date` DESC LIMIT 0,20)
It works but the result set is in two halves, I want to combine the results and order by conceeded whether the team is home or away. Do I need an alias to do this?
Thank you.
Try to make a UNION query with the fields you need, renaming the for or against fields so that they have the same name. Then select everything from this table union and order by the renamed field:
select * from
((SELECT matches.*, teams.*, outcomes.against as goals
FROM matches,teams,outcomes
WHERE
matches.home_team_id=11
AND matches.away_team_id=teams.team_id
AND matches.score_id=outcomes.outcome_id
)
UNION
(SELECT matches.*, teams.*, outcomes.for as goals
FROM matches,teams,outcomes
WHERE matches.away_team_id=11
AND matches.home_team_id=teams.team_id
AND matches.score_id=outcomes.outcome_id
)) as union_table
order by goals, date desc limit 0,20;
This query executes perfectly in MySQL database.
since you already have the two halves you can just select everything from your query and sort accordingly:
SELECT * FROM
(
(SELECT * FROM `matches`,`teams`,`outcomes`
WHERE `home_team_id`=11 AND `matches`.away_team_id=`teams`.team_id
AND `matches`.score_id=`outcomes`.outcome_id
ORDER BY `against`,`date` DESC LIMIT 0,20)
UNION
(SELECT * FROM `matches`,`teams`,`outcomes`
WHERE `away_team_id`=11 AND `matches`.home_team_id=`teams`.team_id
AND `matches`.score_id=`outcomes`.outcome_id
ORDER BY `for`,`date` DESC LIMIT 0,20)
) as results order by results.conceeded asc
Related
Playerbase have 3 columns: PlrName, TeamTag, Score
I need to sort players grouping them by TeamTag. And put teams with best summarized score above.
So want to figure out what query will help make this:
PlrName|TeamTag|Score PlrName|TeamTag|Score
-------------------------------------------------------
Player1|TeamThr|0 Player6|TeamThr|9 \
Player2|TeamTwo|2 Player1|TeamThr|0 > 9
Player3|TeamOne|4 Player4|TeamThr|0 /
Player4|TeamThr|0 Player5|TeamOne|4 \
Player5|TeamOne|4 became-> Player3|TeamOne|4 > 8
Player6|TeamThr|9 Player8|TeamOne|0 /
Player7|TeamTwo|2 Player2|TeamTwo|2 \
Player8|TeamOne|0 Player7|TeamTwo|2 > 6
Player9|TeamTwo|2 Player9|TeamTwo|2 /
added:
With this query i can get an array(?) of TeamTag's ordered by team score:
SELECT TeamTag FROM Playerbase GROUP BY team ORDER BY SUM(Score) DESC
..can I sort then PlayerBase using this "array"? Prefably within one query :)
Also i need to get full lines (using *), not only three fields.
If your dbms doesn't support window functions (any MySQL version below 8.0):
SELECT PlrName, TeamTag, Score FROM table a
LEFT JOIN
(SELECT PlrName, TeamTag, Score ,SUM(score) ts FROM table GROUP BY TeamTag) b
ON a.TeamTag=b.TeamTag
ORDER BY b.ts DESC, a.TeamTag, score DESC;
Try this
; with cte as (
select TeamTag, sum(Score) as Sum
from tablename)
select t.PlrName, t.teamtag, t.Score from tablename as t inner join cte as c
on t.teamtag=c.teamtag order by c.sum desc, t.score desc
Assuming your dbms supports window functions
select PlrName, TeamTag, Score
from (
select PlrName, TeamTag, Score, sum(Score) over (partition by TeamTag) ms
from tablename ) t
order by ms desc, TeamTag, Score desc
EDIT changed max() to sum() as OP refined the problem explanation.
I made it like this, but feel little uncomfortable about sql :D
SELECT * FROM `Playerbase` as T1
JOIN
(SELECT TeamTag, SUM(Score) AS Sum FROM `Playerbase` GROUP BY TeamTag ORDER BY Sum DESC) AS T2
ON T2.TeamTag = T1.TeamTag
Didn't make what i was trying to, but anyway thanks for answers. They helped me to understand a bit more :D
I am having trouble writing a query for the following problem. I have tried some existing queries but cannot get the results I need.
I have a results table like this:
userid score timestamp
1 50 5000
1 100 5000
1 400 5000
1 500 5000
2 100 5000
3 1000 4000
The expected output of the query is like this:
userid score
3 1000
1 1000
2 100
I want to select a top list where I have n best scores summed for each user and if there is a draw the user with the lowest timestamp is highest. I really tried to look at all old posts but could not find one that helped me.
Here is what I have tried:
SELECT sum(score) FROM (
SELECT score
FROM results
WHERE userid=1 ORDER BY score DESC LIMIT 3
) as subquery
This gives me the results for one user, but I would like to have one query that fetches all in order.
This is a pretty typical greatest-n-per-group problem. When I see those, I usually use a correlated subquery like this:
SELECT *
FROM myTable m
WHERE(
SELECT COUNT(*)
FROM myTable mT
WHERE mT.userId = m.userId AND mT.score >= m.score) <= 3;
This is not the whole solution, as it only gives you the top three scores for each user in its own row. To get the total, you can use SUM() wrapped around that subquery like this:
SELECT userId, SUM(score) AS totalScore
FROM(
SELECT userId, score
FROM myTable m
WHERE(
SELECT COUNT(*)
FROM myTable mT
WHERE mT.userId = m.userId AND mT.score >= m.score) <= 3) tmp
GROUP BY userId;
Here is an SQL Fiddle example.
EDIT
Regarding the ordering (which I forgot the first time through), you can just order by totalScore in descending order, and then by MIN(timestamp) in ascending order so that users with the lowest timestamp appears first in the list. Here is the updated query:
SELECT userId, SUM(score) AS totalScore
FROM(
SELECT userId, score, timeCol
FROM myTable m
WHERE(
SELECT COUNT(*)
FROM myTable mT
WHERE mT.userId = m.userId AND mT.score >= m.score) <= 3) tmp
GROUP BY userId
ORDER BY totalScore DESC, MIN(timeCol) ASC;
and here is an updated Fiddle link.
EDIT 2
As JPW pointed out in the comments, this query will not work if the user has the same score for multiple questions. To settle this, you can add an additional condition inside the subquery to order the users three rows by timestamp as well, like this:
SELECT userId, SUM(score) AS totalScore
FROM(
SELECT userId, score, timeCol
FROM myTable m
WHERE(
SELECT COUNT(*)
FROM myTable mT
WHERE mT.userId = m.userId AND mT.score >= m.score
AND mT.timeCol <= m.timeCol) <= 3) tmp
GROUP BY userId
ORDER BY totalScore DESC, MIN(timeCol) ASC;
I am still working on a solution to find out how to handle the scenario where the userid, score, and timestamp are all the same. In that case, you will have to find another tiebreaker. Perhaps you have a primary key column, and you can choose to take a higher/lower primary key?
Query for selecting top three scores from table.
SELECT score FROM result
GROUP BY id
ORDER BY score DESC
LIMIT 3;
Can you please try this?
SELECT score FROM result GROUP BY id ORDER BY score DESC, timestamp ASC LIMIT 3;
if 2 users have same score then it will set order depends on time.
You can use a subquery
SELECT r.userid,
( SELECT sum(r2.score)
FROM results r2
WHERE r2.userid = r.userid
ORDER BY score DESC
LIMIT 3
) as sub
FROM result r
GROUP BY r.userid
ORDER BY sub desc
You should do it like this
SELECT SUM(score) as total, min(timestamp) as first, userid FROM scores
GROUP BY userid
ORDER BY total DESC, first ASC
This is way more efficient than sub queries. If you want to extract more fields than userid, then you need to add them to the group by.
This will of cause not limit the number of scores pr user, which indeed seems to require a subquery to solve.
I need to show ordered 20 records on my grid but I can't use LIMIT because of my generator(Scriptcase) using LIMIT to show lines per page. It's generator's bug but I need to solve it for my project. So is it possible to show 20 ordered record from my table with a query?
As from comments,if you can't use limit then you can rank your results on basis of some order and in parent select filter limit the results by rank number
select * from (
select *
,#r:=#r + 1 as row_num
from your_table_name
cross join (select #r:=0)t
order by some_column asc /* or desc*/
) t1
where row_num <= 20
Demo with rank no.
Another hackish way would be using group_concat() with order by to get the list of ids ordered on asc/desc and substring_index to pick the desired ids like you need 20 records then join with same table using find_in_set ,But this solution will be very expensive in terms of performance and group_concat limitations if you need more than 20 records
select t.*
from your_table_name t
join (
select
substring_index(group_concat(id order by some_column asc),',',20) ids_list
from your_table_name
) t1 on (find_in_set(t.id , t1.ids_list) > 0)
Demo without rank
What about SELECT in SELECT:
SELECT *
FROM (
-- there put your query
-- with LIMIT 20
) q
So outer SELECT is without LIMIT and your generator can add own.
In a Scriptcase Grid, you CAN use Limit. This is a valid SQL query that selects only the first 20 records from a table. The grid is set to show only 10 records per page, so it will show 20 results split in a total of 2 pages:
SELECT
ProductID,
ProductName
FROM
Products
LIMIT 20
Also the embraced query works out well:
SELECT
ProductID,
ProductName
FROM
(SELECT
ProductID,
ProductName
FROM Products LIMIT 20) tmp
I think what I need to do can be done using one query, but I'm really not sure - and I'd like to avoid performing a query and then sorting the resultant array if possible.
Basically, I have one table, which includes the following columns:
product_name, price, sold
From these columns, I'd like to do the following:
Select the highest 20 values from the 'sold' column DESC;
Order the 20 results by price ASC.
Sounds so simple, but can't figure out how to accomplish this to save my life, and SQL is not my strong point. If anyone could help out, it would be appreciated!
You can use subqueries for this:
select t.*
from (select t.*
from t
order by sold desc
limit 20
) t
order by price asc
You have a query that does a bunch of stuff. I'll call this . Here is what you do:
select t.*
from (select t.*
from (<subquery
) t
order by sold desc
limit 20
) t
order by price asc
I think this will do what you are looking for:
select * from table
order by sold desc, price asc
Thanks for looking, I'm trying to get 20 entries from the database randomly and unique, so the same one doesn't appear twice. But I also have a questionGroup field, which should also not appear twice. I want to make that field distinct, but then get the ID of the field selected.
Below is my NOT WORKING script, because it does the ID as distinct too which
SELECT DISTINCT `questionGroup`,`id`
FROM `questions`
WHERE `area`='1'
ORDER BY rand() LIMIT 20
Any advise is greatly appreciated!
Thanks
Try doing the group by/distinct first in a subquery:
select *
from (select distinct `questionGroup`,`id`
from `questions`
where `area`='1'
) qc
order by rand()
limit 20
I see . . . What you want is to select a random row from each group, and then limit it to 20 groups. This is a harder problem. I'm not sure if you can do this accurately with a single query in mysql, not using variables or outside tables.
Here is an approximation:
select *
from (select `questionGroup`
coalesce(max(case when rand()*num < 1 then id end), min(id)) as id
from `questions` q join
(select questionGroup, count(*) as num
from questions
group by questionGroup
) qg
on qg.questionGroup = q.questionGroup
where `area`='1'
group by questionGroup
) qc
order by rand()
limit 20
This uses rand() to select an id, taking, on average two per grouping (but it is random, so sometimes 0, 1, 2, etc.). It chooses the max() of these. If none appear, then it takes the minimum.
This will be slightly biased away from the maximum id (or minimum, if you switch the min's and max's in the equation). For most applications, I'm not sure that this bias would make a big difference. In other databases that support ranking functions, you can solve the problem directly.
Something like this
SELECT DISTINCT *
FROM (
SELECT `questionGroup`,`id`
FROM `questions`
WHERE `area`='1'
ORDER BY rand()
) As q
LIMIT 20