I have a table, and would like to sort by following rule.
I do the SQL as:
(1) select * from table orderby rank;
(2) select * from table orderby LENGTH(str);
but how can I combine those two SQLs base on (if rank>0) statment?
the idea would be like
subTable_1 which rank>0, than sort by rank;
subTable_2 which rank==0, than sort by str.length;
result=subTable_1 + subTable_2;
Many thanks
table:
| str |rank|
| ab | 2 |
| abcd | 5 |
| abc | 0 |
| a | 0 |
result:
| str |rank|
| abcd | 5 |
| ab | 2 |
| a | 0 |
| abc | 0 |
Pretty simple. Just try the following:
SELECT * FROM table
ORDER BY rank DESC, LENGTH(str) ASC;
Since rank of 0 will always be last in the list when sorted DESC, you can use the simple order by that sawrar026 shows:
SELECT * FROM table
ORDER BY rank DESC, LENGTH(str)
If you had a different condition, or if rank could be negative and you only wanted to sort where it was zero, you'd want two case statements, so you can control the order, changing the criteria in the case statements to suit:
SELECT *
FROM Table1
ORDER BY CASE WHEN rank>0 THEN rank ELSE 0 END DESC
,CASE WHEN rank=0 THEN LENGTH(str) ELSE 0 END
Related
My MySQL table having column with comma separated numbers. See below example -
| style_ids |
| ---------- |
| 5,3,10,2,7 |
| 1,5,12,9 |
| 6,3,5,9,4 |
| 8,3,5,7,12 |
| 7,4,9,3,5 |
So my expected result should have top 5 numbers with maximum appearance count in descending order as 5 rows as below -
| number | appearance_count_in_all_rows |
| -------|----------------------------- |
| 5 | 5 |
| 3 | 4 |
| 9 | 3 |
| 7 | 2 |
| 4 | 2 |
Is it possible to get above result by MySQL query ?
As already alluded to in the comments, this is a really bad idea. But here is one way of doing it -
WITH RECURSIVE seq (n) AS (
SELECT 1 UNION ALL SELECT n+1 FROM seq WHERE n < 20
), tbl (style_ids) AS (
SELECT '5,3,10,2,7' UNION ALL
SELECT '1,5,12,9' UNION ALL
SELECT '6,3,5,9,4' UNION ALL
SELECT '8,3,5,7,12' UNION ALL
SELECT '7,4,9,3,5'
)
SELECT seq.n, COUNT(*) appearance_count_in_all_rows
FROM seq
JOIN tbl ON FIND_IN_SET(seq.n, tbl.style_ids)
GROUP BY seq.n
ORDER BY appearance_count_in_all_rows DESC
LIMIT 5;
Just replace the tbl cte with your table.
As already pointed out you should fix the data if possible.
For further details read Is storing a delimited list in a database column really that bad?.
You could use below answer which is well explained here and a working fiddle can be found here.
Try,
select distinct_nr,count(distinct_nr) as appearance_count_in_all_rows
from ( select substring_index(substring_index(style_ids, ',', n), ',', -1) as distinct_nr
from test
join numbers on char_length(style_ids) - char_length(replace(style_ids, ',', '')) >= n - 1
) x
group by distinct_nr
order by appearance_count_in_all_rows desc ;
I have a table with a column to maintain the state of the record. i.e.
-----------------------------
| id | desc | state |
-----------------------------
| 1 | desc 1 | Complete |
| 2 | desc 2 | Open |
| ... | ... | ... |
-----------------------------
I want fetch the records in the order of 'Open' followed by 'Complete'. Can I get this done using one SQL query? If so, how should I write it?
Yes, you could do this with the ORDER BY statement and FIELD function:
SELECT * FROM table1 ORDER BY FIELD(state, 'Open', 'Complete')
Try something like this:
select *
from table_name
order by decode (state, 'Open', 1, 'Complete', 2, 3)
We have a DB called transaction. It has user_id, date, value and so on. I use pagination in my query also. I have thousands of record in my table which has user_id equal to 2 or other value. put the user_id = 2 at the very last page.
I want to sort the result like this:
sort the results by date but if the user_id= 2 , put all results associated with the user_id= 2 at the end.
to be more clear, I show you what I want in the below.
-------------------------------------
| ID | user_id | date | ......
-------------------------------------
| 1 | 10 | 2018-10-20 |
-------------------------------------
| 2 | 11 | 2018-10-21 |
-------------------------------------
| 3 | 2 | 2018-10-22 |
-------------------------------------
| 4 | 2 | 2018-10-23 |
the results have to be like this:
first: ID = 2, second: ID = 1, third: ID = 4, last: ID = 3
tip *:
I use field function but unfortunately in vain.
ORDER BY FIELD(user_id, 2) DESC, date DESC
You may try using a CASE expression in your ORDER BY clause:
SELECT *
FROM yourTable
ORDER BY
CASE WHEN user_id = 2 THEN 1 ELSE 0 END,
date DESC;
I'm not sure if you want each group sorted by date ascending or descending. If you want ascending date order, then remove the DESC keyword at the end of my query.
I have a problem here trying to get one of my CASE WHEN statement to query each row for something called is_op as it's returning the same number for all rows. Here is the code:
SELECT `mid`, `message`, `created_at`,
CASE WHEN (SELECT `uid` FROM `bulletin_message` WHERE `bid` = 1 ORDER BY `mid` ASC LIMIT 1) = 5 THEN 1 ELSE 0 END AS `is_op`,
CASE WHEN `bulletin_message`.`uid` = 5 THEN 1 ELSE 0 END AS `is_me`
FROM`bulletin_message`
WHERE `bid` = 1
GROUP BY `mid`
ORDER BY `mid` ASC
As you can see I'm trying to select messages with the condition bid must equal to 1 and uid must equal to 5. While is_me returns the correct value for each row, is_op isn't reflecting the correct value for all the rows at all. It displays 1 at the result of the statement, rather than showing if a user is an OP or not based on the oldest value of mid or created_at. I don't think I am correctly querying each row like is_me statement.
This is all the data of the table:
mid = message uid; bid = bulletin/thread uid; uid = user uid
| mid | bid | uid | message | created_at |
---------------------------------------------------
| 3 | 1 | 5 | ... | ... |
| 5 | 1 | 6 | ... | ... |
| 6 | 2 | 7 | ... | ... |
| 9 | 1 | 5 | ... | ... |
| 10 | 1 | 7 | ... | ... |
| 11 | 1 | 6 | ... | ... |
What can be done to improve this line of code so that it can query each row? Thank you!
Edit: OP is Original Poster, sorry for not clarifying that! It's usually the person who post the first in each bid.
The problem is your subquery is based on a fixed predicate, ``bid= 1, so it is bound to return the same value for all rows.
Something like this would make more sense:
SELECT `mid`, `message`, `created_at`,
CASE WHEN (SELECT `uid`
FROM `bulletin_message` AS t2
WHERE t1.`bid` = t2.`bid`
ORDER BY `mid` ASC LIMIT 1) = t1.`uid`
THEN 1
ELSE 0
END AS `is_op`
FROM`bulletin_message` AS t1
ORDER BY `mid` ASC
The subquery is correlated using bid field: it returns the OP of the current thread.
I have a table like this:
startyearmonthday| id
20130901 | 1
20131004 | 2
20130920 | 3
20131105 | 4
20131009 | 5
I want to write a query where I can return a table like this:
startyearmonthday| id | endyearmonthday
20130901 | 1 | 20130920
20130920 | 3 | 20131004
20131004 | 2 | 20131009
20131009 | 5 | 20131105
20131105 | 4 | null
So I want the end date based on the next earliest start date after the current start date. I imagine some sort of join is involved but I can't figure it out...
I would be inclined to do this with a correlated subquery:
select t.*,
(select startyearmonthday
from t t2
where t2.startyearmonthday > t.startyearmonthday
order by t2.startyearmonthday
limit 1
) as endyearmonthday
from t;
As with your earlier question, this will run pretty quickly with an index on t(startyearmonthday).
Try this (assuming there are no repeated rows):
select a.*, b.startyearmonthday as endyearmonthday
from table_name a
left join table_name b
on b.startyearmonthday > a.startyearmonthday and not exists(select startyearmonthday from table_name c where a.startyearmonthday < c.startyearmonthday and c.startyearmonthday < b.startyearmonthday)