I am doing the next query:
SELECT id, name, keyt
FROM table
WHERE id = (SELECT t2.id FROM table t2 WHERE t2.keyt=21 ORDER BY RAND() LIMIT 1)
Supposing table is like this:
| id | name | keyt |
+ ------------------------- +
| 1 | Hello | 21 |
| 3 | Katzet | 1 |
| 1 | Welcome | 1 |
| 2 | Two | 21 |
| 2 | Other | 1 |
It should return one of this pairs:
Hello | Welcome (id 1 in common)
Two | Other (id 2 in common)
So, the idea is:
Get one id, which has the keyt value set to 21
Then, get all the rows with this selected id (independently of all the other keyt values)
If I do as you suggested... I would get mixed id values, and all result rows must have the same id.
SELECT x.*
FROM my_table x
JOIN
( SELECT id
FROM my_table
WHERE keyt = 21
ORDER
BY RAND() LIMIT 1
) y
ON y.id = x.id;
The subquery in this query
SELECT id, name, keyt
FROM table
WHERE id = (SELECT t2.id FROM table t2 WHERE t2.keyt=21 ORDER BY RAND() LIMIT 1)
would return only one record as it has LIMIT 1 added at the end.
Also, in your question, the table contains only 1 record for which
value of keyt = 21, due to which you're getting only one record.
If you want more records, you should remove the LIMIT. In that case you may rephrase your query as:
SELECT id, name, keyt
FROM table
WHERE id IN (SELECT t2.id FROM table t2 WHERE t2.keyt=21 ORDER BY RAND())
Hope this is what you expected. As your actual goal is not very clear from the question.
Your table has two 21 in the keyt column so your subquery in the where clause returns 2 values if id that is 1 and 2.So what you need to do is instead of using an equal to operator "=" use IN operator in the where clause.
SELECT id, name, keyt FROM table WHERE id IN (SELECT t2.id FROM table t2 WHERE t2.keyt=21 ORDER BY RAND())
Related
Lets say we have a table that looks like this:
+---------------+----------------+-------------------+
| ID | random_string | time |
+---------------+----------------+-------------------+
| 2 | K2K3KD9AJ |2022-07-21 20:41:15|
| 1 | SJQJ8JD0W |2022-07-17 23:46:13|
| 1 | JSDOAJD8 |2022-07-11 02:52:21|
| 3 | KPWJOFPSS |2022-07-11 02:51:57|
| 1 | DA8HWD8HHD |2022-07-11 02:51:49|
------------------------------------------------------
I want to select the last 3 entries into the table, however they must all have separate ID's.
Expected Result:
+---------------+----------------+-------------------+
| ID | random_string | time |
+---------------+----------------+-------------------+
| 2 | K2K3KD9AJ |2022-07-21 20:41:15|
| 1 | SJQJ8JD0W |2022-07-17 23:46:13|
| 3 | KPWJOFPSS |2022-07-11 02:51:57|
------------------------------------------------------
I have already tried:
SELECT DISTINCT id FROM table ORDER BY time DESC LIMIT 3;
And:
SELECT MIN(id) as id FROM table GROUP BY time DESC LIMIT 3;
If you're not on MySQL 8, then I have two suggestions.
Using EXISTS:
SELECT m1.ID,
m1.random_string,
m1.time
FROM mytable m1
WHERE EXISTS
(SELECT ID
FROM mytable AS m2
GROUP BY ID
HAVING m1.ID=m2.ID
AND m1.time= MAX(time)
)
Using JOIN:
SELECT m1.ID,
m1.random_string,
m1.time
FROM mytable m1
JOIN
(SELECT ID, MAX(time) AS mxtime
FROM mytable
GROUP BY ID) AS m2
ON m1.ID=m2.ID
AND m1.time=m2.mxtime
I've not test in large data so don't know which will perform better (speed) however this should return the same result:
Here's a fiddle
Of course, this is considering that there will be no duplicate of exact same ID and time value; which seems to be very unlikely but still it's possible.
Using MySql 8 an easy solution is to assign a row number using a window:
select Id, random_string, time
from (
select *, Row_Number() over(partition by id order by time desc) rn
from t
)t
where rn = 1
order by time desc
limit 3;
See Demo
This question already has answers here:
Retrieving the last record in each group - MySQL
(33 answers)
Closed 2 years ago.
My sample table:
ID | Post_id | Score
1 | 1 | 33
2 | 1 | 43
3 | 1 | 27
4 | 1 | 66
I want to get rows with the lowest value (Score). In this case it is:
ID | Post_id | Score
3 | 1 | 27
My query:
SELECT * FROM table WHERE post_id = '1' GROUP BY post_id ORDER BY Score ASC
But that doesn't work because it returns me: Score: 33
How to fix it? What if I have thousands of rows and want post_id to be unique for the lowest values?
You must use subquery selecting min values for each post_id.
SELECT a.* FROM records a
JOIN
( SELECT post_id, MIN(score) as min_score
FROM records GROUP BY post_id
) b
ON a.score=b.min_score;
Output
| id | post_id | score |
| --- | ------- | ----- |
| 3 | 1 | 27 |
| 5 | 2 | 20 |
View on DB Fiddle
For a single id, just remove the group by and use limit:
SELECT *
FROM table
WHERE post_id = 1
ORDER BY Score ASC
LIMIT 1;
I assume that post_id is a number. Compare numbers to numbers, not to strings.
EDIT:
If you want this per post_id, then just use a correlated subquery:
select t.*
from t
where t.score = (select min(t2.score) from t t2 where t2.post_id = t.post_id);
If you may have multiple rows with the lowest score, you can do it with a sub-query :
SELECT *
FROM test
WHERE post_id = 1
AND score = (
SELECT MIN(score)
FROM test
WHERE post_id = 1
)
Fiddle : https://www.db-fiddle.com/f/3ppntnA77HFpKRU82h32Gv/1
IF you're using MySQL v8.0, you can use the ROW_NUMBER() function to order the result. That way you can choose the row with the lower score and return everything from it:
select
sq.id, sq.post_id, sq.score
from
(select id, post_id, score
, row_number() over (partition by post_id order by score) RowNo
from test) sq
where sq.RowNo = 1
Here is a Fiddle to test the code: https://www.db-fiddle.com/#&togetherjs=8dHSCs50Iq
I also included another post_id beside your sample data, to demonstrate how it reacts to multiple post_id's
The below should do the trick:
Select
id,
score,
Post_id,
min(score)
from
table
where
score = min(score);
My table:
id | request | subject | date
1 | 5 | 1 | 576677
2 | 2 | 3 | 576698
3 | 5 | 1 | 576999
4 | 2 | 3 | 586999
5 | 2 | 7 | 596999
Need to select unique records by two columns(request,subject). But if we have different pairs of request-subject(2-3, 2-7), this records should be excluded from resulted query.
My query now is:
SELECT MAX(id), id, request, subject, date
FROM `tbl`
GROUP BY request, subject
having count(request) > 1
order by MAX(id) desc
How to exclude record with id=4, id=5 from this query? Thanks!
You may group by request, and then check for every group if all subjects in it are equal. You could do it using MIN() and MAX():
SELECT request, MIN(subject) AS subject
FROM table_1
GROUP BY request
HAVING MIN(subject) = MAX(subject)
As for your update, I assume you want all the fields for the max ID in the group (in your example, ID 3). The query would then look like this one:
SELECT *
FROM table_1 t
WHERE t.id IN (SELECT MAX(s.id)
FROM table_1 s
GROUP BY s.request
HAVING MIN(s.subject) = MAX(s.subject))
ORDER BY t.id
You can try this.
select * from MyTable T1
WHERE NOT EXISTS( SELECT * FROM MyTable T2
WHERE T1.id <> T2.id
and T1.request = T2.request
and T1.subject <> T2.subject)
Sql Fiddle
Considering this table:
+-----+--------+
| id | value |
+-----+--------+
| 1 | 22 |
+-----+--------+
| 2 | 12 |
+-----+--------+
| 3 | 22 |
+-----+--------+
| 4 | 22 |
+-----+ -------+
I can select all where the column value is duplicated like so:
select value from table having count(value) > 1 ;
This will output the Ids 1,3 and 4.
What I'm attempting to do is select where duplicates, but leaving 1 (one) duplicate un selected, so the above would output only the Ids 3 and 4 (or 1 and 3 etc... the duplicate omitted does not matter, only that it is.
How can I achieve this?
This question IS NOT a duplicate of
Using LIMIT within GROUP BY to get N results per group?
You could use an aggregatio function for filter a value for id and the select all the others
select * from table
where (value, id) not in (
select value, max(id)
from table
group by value
having count(value) > 1
)
;
You can do either as:
select *
from test t1
where exists (select 1
from test t2
where t2.value = t1.value
having count(value)>1)
limit 2
OR:
select t1.*
from test t1 inner join
(select value from test t2 having count(value)>1) t2
on t1.value = t2.value
limit 2;
MY Table is
id position some data
---|--------|------------|
1 | 1 | data |
1 | 2 | data |
2 | 1 | data |
2 | 2 | data |
5 | 1 | data |
5 | 2 | data |
5 | 3 | data |
how do i format it into the following. so that it shows only the unique ID with the highest position as following. The data is a longitude and latitude, so it should only return the highest position long and lat.
id position some data
---|--------|------------|
1 | 2 | data |
2 | 2 | data |
5 | 3 | data |
You can join on a maximum-grouped set;
select *
from the_table inner join (
select id, max(position) as max_pos
from the_table
group by id
) as T on the_table.id = T.id and the_table.position = T.max_pos
order by the_table.id
Supposing that data responds to an aggregate appropriately you can do this:
SELECT id, MAX(position), MAX(some_data)
FROM My_Table
GROUP BY id
If not, I believe that version has the necessary OLAP functions:
WITH Max_Data as (SELECT id, position, data,
ROW_NUMBER() OVER(PARTITION BY id
ORDER BY position DESC) as rowNum
FROM My_Table)
SELECT id, position, data
FROM Max_Data
WHERE rowNum = 1
You'll want an index that includes position for best performance.
SELECT id, MAX(position), data
FROM yourtable
GROUP BY id
assming that the id field is your memberid. This'll fetch the largest position for each id. However, data is another matter. Do you need the actual data that's in the same record as the MAX(position), or just any data?
If you need it to be the data from the same record as the max id, then
SELECT yourtable.id, yourtable.position, yourtable.data
FROM yourtable
LEFT JOIN (
SELECT id, MAX(position) AS position
FROM yourtable AS child
GROUP BY id
) AS child ON (yourtable.id = child.id AND yourtable.position = child.position