Arrange data in specific order - mysql

I have a user table that contain 8 records. I want to arrange the data in descending order on the basis of field id (that is a primary key of that table) but except id 3 and 5. So eventually the result should be like
id name
-- ----
3 peter
5 david
8 john
7 stella
6 jim
4 jack
2 nancy
1 scott
Except id 3 and 5 rest of the data should be arranged in descending order and 3 and 5 should come in ascending order.

SELECT * FROM user ORDER BY IF(id=3 OR id=5, id, ~id) ASC

something like this:
order by
case
when id = 3 then 999
when id = 5 then 998
else id
end desc
This assumes that you really don't have more than 8 rows. Otherwise you must change the "magic" numbers that move 3 and 5 to the top.

I think the trick here is to use an enum.
SELECT id, name FROM my_table WHERE id IN (3, 5) ORDER BY ASC
UNION
SELECT id, name FROM my_table WHERE id NOT IN(3, 5) ORDER BY DESC

In MySQL, there is a function called FIELD which *returns zero if a value is not found on the list` eg,
SELECT *
FROM tableName
ORDER BY FIELD(id, 5, 3) DESC, id DESC
SQLFiddle Demo
FIELD

Related

How can I get the second higher number in a query

Example, Lets suppose I have a table like next one:
id | start | userId
1 3 1
2 2 2
3 5 1
Now, I want to get all the row information for the second higher value of the column start related to some userId. So, if userId equals to 1 I'm expecting to get the next result:
(id, start, userId) = (1,3,1)
I have tried this query:
SELECT id, max(start) FROM table_user WHERE userId = 1;
But this gives me the higher number.
You can do this easy using ordering by column start and the features of LIMIT, like this:
SELECT
*
FROM
table_user
WHERE
userId = 1
ORDER BY
`start` DESC LIMIT 1, 1
You can check this online also: DB-Fiddle

How to delete record from table if its count > 5

I have following table:
id systemid value
1 1 0
2 1 1
3 1 3
4 1 4
6 1 9
8 1 10
9 1 11
10 1 12
Now here i have 8 records of systemid = 1 so now i want to keep only latest 3 records (desc order) and delete older records whose systemid=1
I want output like :
id systemid value
8 1 10
9 1 11
10 1 12
I just want to delete old records of systemid=1 only if its count > 5 and keep its latest 3 records.
How can i do this in query ?
If you do not always have 8 records and want to select the last 3 records from the table where systemid=1 however many records there are, then a good way to do this is to use the IN selector in your SQL statement.
It would be good is you could do this simply using the statement
SELECT * FROM mytable WHERE id IN (SELECT id FROM `mytable` WHERE systemid=1 ORDER BY id DESC LIMIT 3)
However this is not yet supported in MySQL and if you try this then you will get an error like
...doesn't yet support 'LIMIT & IN/ALL/SOME subquery'
So you need a workaround as follows (using SELECT to test):
SET #myvar := (SELECT GROUP_CONCAT(id SEPARATOR ',') AS myval FROM (SELECT * FROM `mytable` WHERE systemid=1 ORDER BY id DESC LIMIT 3 ) A GROUP BY A.systemid);
SELECT * FROM mytable WHERE FIND_IN_SET(id,#myvar);
The way that this works (first line) is to set a variable called #myvar which will hold the last 3 values as a comma separated string if id values. In your case
9,8,10
Then select the rows where the 'id' is in this string.
Replace the 'SELECT *' with 'DELETE FROM' to finalize the result so your query will be
SET #myvar := (SELECT GROUP_CONCAT(id SEPARATOR ',') AS myval FROM (SELECT * FROM `mytable` WHERE systemid=1 ORDER BY id DESC LIMIT 3 ) A GROUP BY A.systemid);
DELETE FROM mytable WHERE NOT FIND_IN_SET(id,#myvar);
I hope that this helps.
Try this to keep the latest three records that have system_id equal to 1 and count is greater than 5:
DELETE FROM <table_name> WHERE system_id = 1 AND value > 5 ORDER BY id DESC LIMIT 3
You can specify an offset with the LIMIT keyword in your query so the newest 5 rows are kept. According to MySQL's documentation, however, there's no easy way to limit from an offset all the way to the last; instead, they suggest this:
To retrieve all rows from a certain offset up to the end of the result set, you can use some large number for the second parameter.
So this SQL should do the trick:
DELETE FROM table where systemid = 1 ORDER BY value DESC LIMIT 5,45484848
This is going to be a very long query. What you need is for every system_id that have more than 5 records you want to delete the record that are less than ranking 3.
I'm going to seperate the queries and use names for them at the end.
1_ ranking_query: abriviation is RQ
In mysql there is no rownum or something like that hope this query return the records ranked from ghe first to the last.
SELECT
#rank := #rank + 1 as rank,
id,
system_id,
value
FROM table_name, (select #rank:=0) as rt
order by system_id, value desc
this will rank every record in your table and the main benefit is the record with the same system_id will be after each other in desc order
system_id value rank
1. 10. 1
1. 9. 2
1. 7. 3
1. 5. 4
1. 3. 5
1. 2. 6
2. 12. 7
2. 10. 8
3. 11. 9
........
......
3. 1. 15
In this example for system_id 1 we need to keep only the three first (1,2,3) record same thing for system_id 3 (9,10,11)
2_ filter_query. Abriviation is: FQ
Because you want to delete based on count 5 we need this extra query
SELECT
system_id
FROM table_name
GROUP BY system_id
having count(*) > 5
result:
system_id
1
3
4_ third_query abriviation: RQD
a query to know which rank should we start do delete from for every system_id in mysql we need to rewrite the first query again but here i'm going to use Abriviation to keep the answer short.
SELECT
system_id,
min_rank + 3 from_rank
FROM (
SELECT
RQ2.system_id,
min(RQ2.rank) as min_rank
FROM (rank_query) RQ2
GROUP BY system_id) RS
so for the same example the we going to have this result
system_id. from_rank
1. 4
2. 9 -- this record will be removed by the filter_query
3. 12
FINAL QUERY:
so we need to delete record that exist in filter query and the ranking is bigger than from_rank.
DELETE FROM table_name WHERE
id in (
SELECT
RQ.id
FROM
rank_query RQ INNER JOIN filter_query FQ ON rq.system_id = FQ.system_id
INNER JOIN third_query RQD ON RQ.rank >= RQD.from_rank)
I hope this idea work sorry for any syntax error i used my phone to answer i like this kind of query

SQL order by after more than

I am trying SQL to sort results
id | name (table name: student)
-----
1 | jhon
2 | amin
3 | heli
4 | mir
5 | mrs
6 | amr
7 | jonnathan
8 | adhy
When i use this query
select id from studenth where id>='3' order by id DESC limit 2
The result that appears is
id | name (table name: student)
-----
8 | adhy
7 | jonnathan
Whereas I want to sort results after id = 3, I want the data as below
id | name (table name: student)
-----
4 | mir
3 | heli
select * from (select id from student where id >= 3 order by id limit 2) r order by r.id desc
You can use this query. You want everything less than or equal to 4 instead of everything after 3.
select id from student where id<='4' order by id DESC limit 2
You can do some like:
select * from student where id>=3 order by id LIMIT 2
If you want to take the records and sort it in descending order,then you can go for a subquery.
SELECT * FROM
( SELECT *
FROM student
WHERE id>=3 ORDER BY id LIMIT 2) X
ORDER BY X.id DESC
Problem with your Query
select * from student where id>='3' order by id DESC limit 2
The above query will take all the results with id=3 or more and order it in the descending order and with LIMIT 2 it will display only 2 records.
That's why it's displaying the last 2 records.
TRY THIS Use sub query it's easy to understand and fulfill your requirement:
SELECT id, name
FROM studenth
WHERE id IN (SELECT id
FROM studenth
WHERE id >= 3 ORDER BY id LIMIT 2) ORDER BY id DESC
If i understood correctly , you want the data in descending order from id +1 record. the query should be something like below:
select id from studenth where id<='4' order by id DESC limit 2;
Remove single quotes in this id>='3'
select id from student where id>=3 order by id desc limit 2
Update 1:
Order by desc limit 2 problem here use subquery get the result then apply descending .
select * from (select id from student where id >= 3 order by id limit 2) new order by new.id desc
Please try the following...
SELECT id,
name
FROM tblTable
WHERE id >= 3
ORDER BY id DESC
LIMIT ( ( SELECT COUNT( * )
FROM tblTable
WHERE id >= 3 ) - 1 ), 2;
This statement works by sorting the records from tblTable based on the value of id. It then uses LIMIT to select specific records from the sorted list. If there are 20 eligibnle records this equates to LIMIT 19, 2, which will give us the 19th and 20th records.
If you have any questions or comments, then please feel free to post a Comment accordingly.

MySQL group multiple rows based on DISTINCT value

I need to display the last 2 results from a table (results), the results are comprised of several rows with matching submissionId, The number of rows per submission is unknown, and of course I prefer a single query.
Here is the DB table structure
submissionId input value
1 name jay
1 phone 123-4567
1 email test#gmail.com
2 name mo
2 age 32
3 name abe
3 email abe#gmail.com
4 name jack
4 phone 123-4567
4 email jack#gmail.com
Desierd results:
submissionId input value
3 name abe
3 email abe#gmail.com
4 name jack
4 phone 123-4567
4 email jack#gmail.com
Or even better, if I can combine the rows like this:
3 name abe 3 email abe#gmail.com
4 name jack 4 phone 123-4567 4 email jack#gmail.com
One option here is to use a subquery to identify the most recent and next to most recent submissionId:
SELECT submissionId, input, value
FROM yourTable
WHERE submissionId >= (SELECT MAX(submissionId) FROM yourTable) - 1
ORDER BY submissionId
Demo here:
SQLFiddle
Update:
If your submissionId column were really a date type, and you wanted the most recent two dates in your result set, then the following query will achieve that. Note that the subquery in the WHERE clause, while ugly, is not correlated to the outer query. This means that the MySQL optimizer should be able to figure out that it only needs to run it once.
SELECT submissionDate, input, value
FROM yourTable
WHERE submissionDate >=
(SELECT MAX(CASE WHEN submissionDate = (SELECT MAX(submissionDate) FROM yourTable)
THEN '1000-01-01'
ELSE submissionDate
END) FROM yourTable)
ORDER BY submissionDate
SQLFiddle
You can use limit in subqueries in the from clause, so a typical way to write this is:
SELECT submissionDate, input, value
FROM t join
(select distinct submissionDate
from t
order by submissionDate desc
limit 2
) sd
on t.submissionDate = sd.submissionDate;
This is how the query looks like now, so i can get the results with a LIMIT, RANGE, and id/timestamp (with help of Tim and Gordon):
SELECT *
FROM rmyTable t
JOIN
(SELECT DISTINCT sd.submissionId
FROM myTable sd
WHERE sd.questionId = yourId
ORDER BY sd.submissionId
LIMIT 2
) t2
ON t.submissionId = t2.submissionId
WHERE t.formId = yourId
AND dateTime BETWEEN 0000 AND 1111

getting rank of a row in a rowset

I have the following rows :
id name score
1 Bill 0
2 Kim 8
3 Michael 30
4 Doug 22
5 Mellisa 1
When I do SELECT * FROM table ORDER BY score DESC, I get
id name score
4 Doug 22
3 Michael 30
2 Kim 8
5 Mellisa 1
1 Bill 0
Now I want to get only one row, so I'll add a where clause, but problem is the ranking.
I'm producing pseudo ranks in my php code, i.e. the first row in the rowset is assigned rank 1, second is assigned rank 2 and so on...
So when I do SELECT * FROM table WHERE id = 5, apparently all the rank information is lost. How to get over this problem? Is there any way I could get the position of the row in rowset before adding the where clause?
Wrap the query in a subquery so that the rank will be preserved. Here's an example,
-- the example produces rank based on highest score.
SELECT *
FROM
(
SELECT #rank := ifnull(#rank, 0) + 1 Rank,
Id, name, Score
FROM tableName a
ORDER BY Score DESC
) x
WHERE ID = 5
SQLFiddle Demo
SELECT id, name, score, FIND_IN_SET( score, (
SELECT GROUP_CONCAT( score
ORDER BY score DESC )
FROM ScoreDetail)
) AS rank
FROM ScoreDetail
Where id=5
This will solve your problem....