I'm selecting a set of account records from a large table (millions of rows) with integer id values. As basic of a query as one gets, in a sense. What I'm doing us building a large comma separated list, and passing that into the query as an "in" clause. Right now the result is completely unordered. What I'd like to do is get the results back in the order of the values in the "in" clause.
I assume instead I'll have to build a temporary table and do a join instead, which I'd like to avoid, but may not be able to.
Thoughts? The size of the query right now is capped at about 60k each, as we're trying to limit the output size, but it could be arbitrarily large, which might rule out an "in" query anyway from a practical standpoint, if not a physical one.
Thanks in advance.
Actually, this is better:
SELECT * FROM your_table
WHERE id IN (5,2,6,8,12,1)
ORDER BY FIELD(id,5,2,6,8,12,1);
heres the FIELD documentation:
http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_field
A bit of a trick....
SELECT * FROM your_table
WHERE id IN (5,2,6,8,12,1)
ORDER BY FIND_IN_SET(id,'5,2,6,8,12,1') DESC;
note that the list of ID's in the find_in_set is a string, so its quoted.
Also note that without DESC, they results are returned in REVERSE order to what the list specified.
If your query is 60K, that's a sign that you're doing it the wrong way.
There is no other way to order the result set than by using an ORDER BY clause. You could have a complicated CASE clause in your order by listing all the elements in your IN clause again, but then your query would probably be 120K.
I know you don't want to, but you should put the values in the IN clause in a table or a temporary table and join with it. You can also include a SortOrder column in the temporary table, and order by that. Databases like joins. Doing it this way will help your query to perform well.
This is what I get for mysql 8.0. It seems opposite to above answers.
sort in same order as list specified:
SELECT * FROM your_table
WHERE id IN (5,2,6,8,12,1)
ORDER BY FIND_IN_SET(id,'5,2,6,8,12,1');
sort in reverse order as list specified:
SELECT * FROM your_table
WHERE id IN (5,2,6,8,12,1)
ORDER BY FIND_IN_SET(id,'5,2,6,8,12,1') DESC;
You're first query surely uses an order by clause. So, you could just do a join, and use the same order by clause.
For example, if this was your first query
SELECT customer_id
FROM customer
WHERE customer_id BETWEEN 1 AND 100
ORDER
BY last_name
And this was your second query
SELECT inventory_id
FROM rental
WHERE customer_id in (...the ordered list...)
Combined would be
SELECT r.inventory_id
FROM rental r
INNER
JOIN customer c
ON r.customer_id = c.customer_id
WHERE c.customer_id BETWEEN 1 AND 100
ORDER
BY c.last_name
This is what worked for me
SELECT * FROM your_table
WHERE id IN ('5','2','6','8','12','1')
ORDER BY FIELD(id,'5','2','6','8','12','1');
I added the ids in quotes
My database is called: (training_session)
I try to print out some information from my data, but I do not want to have any duplicates. I do get it somehow, may someone tell me what I do wrong?
SELECT DISTINCT athlete_id AND duration FROM training_session
SELECT DISTINCT athlete_id, duration FROM training_session
It works perfectly if i use only one column, but when I add another. it does not work.
I think you misunderstood the use of DISTINCT.
There is big difference between using DISTINCT and GROUP BY.
Both have some sort of goal, but they have different purpose.
You use DISTINCT if you want to show a series of columns and never repeat. That means you dont care about calculations or group function aggregates. DISTINCT will show different RESULTS if you keep adding more columns in your SELECT (if the table has many columns)
You use GROUP BY if you want to show "distinctively" on a certain selected columns and you use group function to calculate the data related to it. Therefore you use GROUP BY if you want to use group functions.
Please check group functions you can use in this link.
https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html
EDIT 1:
It seems like you are trying to get the "latest" of a certain athlete, I'll assume the current scenario if there is no ID.
Here is my alternate solution:
SELECT a.athlete_id ,
( SELECT b.duration
FROM training_session as b
WHERE b.athlete_id = a.athlete_id -- connect
ORDER BY [latest column to sort] DESC
LIMIT 1
) last_duration
FROM training_session as a
GROUP BY a.athlete_id
ORDER BY a.athlete_id
This syntax is called IN-SELECT subquery. With the help of LIMIT 1, it shows the topmost record. In-select subquery must have 1 record to return or else it shows error.
MySQL's DISTINCT clause is used to filter out duplicate recordsets.
If your query was SELECT DISTINCT athlete_id FROM training_session then your output would be:
athlete_id
----------
1
2
3
4
5
6
As soon as you add another column to your query (in your example, the column called duration) then each record resulting from your query are unique, hence the results you're getting. In other words the query is working correctly.
I have a table x :
id lang externalid
1 nl 10
2 nl 11
3 fr 10
From this table I want al the rows for a certain lang and externalid, if the externalid doesn't exist for this lang, I want the row with any other lang.
The subquery sorts the table correct, but when I add the group by, the sort of the subquery is lost. This works in older mysql versions but not in 5.7.
(
SELECT
*
FROM
x
ORDER BY FIELD(lang, "fr") DESC, id
)
as y
group by externalid
I want the query to return the records with id 2 & 3. So for each distinct external id, if possible the lang = 'fr', else any other lang.
How can i solve this problem?
You are talking of given externalid and land. No need to group by externalid hence; use a mere where clause instead.
Combined with ORDER BY and LIMIT you get the record you want (i.e. the desired language if such a record exists, else another one).
select *
from mytable
where externalid = 10
order by lang = 'fr' desc
limit 1;
UPDATE: Okay, according to your comment you want to get the "best" record per externalid. In standard SQL you'd use ROW_NUMBER for this. Other DBMS have further solutions, e.g. Oracle's KEEP FIRST or Postgre's DISTINCT ON. MySQL doesn't support any of these. One way would be to emulate ROW_NUMBER with variables. Another would be to use above query as a subquery per externalid to find the best records:
select *
from mytable
where id in
(
select
(
select m.id
from mytable m
where m.externalid = e.externalid
order by m.lang = 'fr' desc
limit 1
) as best_id
from (select distinct externalid from mytable) e
);
Your subquery generates a result set (a virtual table) that's passed to your outer query.
All SQL queries, without exception, generate their results in unpredictable order unless you specify the order completely in an ORDER BY clause.
Unpredictable is like random, except worse. Random implies you'll get a different order every time you run the query. Unpredictable means you'll get the same order every time, until you don't.
MySQL ordinarily ignores ORDER BY clauses in subqueries (there are a few exceptions, mostly related to subquery LIMIT clauses). Move your ORDER BY to the top level query.
Edit. You are also misusing MySQL's notorious nonstandard extension to GROUP BY.
I have a table containing the primary key NoticeID, the NoticeDate and the notice itself. I wanted to make a query which would find the NoticeDate and notice of the row with the greatest NoticeID.
I tired this:
SELECT NoticeDate, Notice FROM notices WHERE NoticeID=(SELECT MAX(NoticeID))
It just returns the all of the rows.
Please help.
What's important here is that the greatest NoticeID is applied to groups of NoticeDate, implying the need for a GROUP BY.
There are a few ways of approaching a query to get one full record per group (your group is NoticeDate). Probably the easiest is an IN () subquery which returns the MAX(NoticeID) per group:
SELECT
NoticeDate,
Notice
FROM
notices
WHERE
NoticeID IN (SELECT MAX(NoticeID) FROM notices GROUP BY NoticeDate)
That may not be the fastest, however. You may also join against a subquery returning that same MAX(NoticeID). In this case, the subquery produces a table of NoticeID which is joined back to the full table to retrieve the remaining columns for the row it matches when joining.
SELECT
n.NoticeDate,
n.Notice
FROM
notices n
JOIN (
-- Join a subquery to get the max NoticeID per group
SELECT MAX(NoticeID) AS maxid
FROM notices
GROUP BY NoticeDate
) nmax ON n.NoticeID = nmax.maxid
If you want only one row back, then I think the easiest approach is using order by and limit:
SELECT n.*
FROM notices n
ORDER BY NoticeId DESC
LIMIT 1;
I have a table with a million rows, how do i select the most common(the value which appears most in the table) value from a field?
You need to group by the interesting column and for each value, select the value itself and the number of rows in which it appears.
Then it's a matter of sorting (to put the most common value first) and limiting the results to only one row.
In query form:
SELECT column, COUNT(*) AS magnitude
FROM table
GROUP BY column
ORDER BY magnitude DESC
LIMIT 1
This thread should shed some light on your issue.
Basically, use COUNT() with a GROUP BY clause:
SELECT foo, COUNT(foo) AS fooCount
FROM table
GROUP BY foo
ORDER BY fooCount DESC
And to get only the first result (most common), add
LIMIT 1
To the end of your query.
In case you don't need to return the frequency of the most common value, you could use:
SELECT foo
FROM table
GROUP BY foo
ORDER BY COUNT(foo) DESC
LIMIT 1
This has the additional benefit of only returning one column and therefore working in subqueries.