ORDER BY separately positive & negative numbers in MySQL statement - mysql

I have a MySQL table and would like to return the rows based on a column value in this order:
First ascending order if the column >=0
Then descending order if the column <0
E.g. 0,2,4,7,-2,-3,-5

Can use SIGN to sort the positive numbers to the top, then take the absolute value with ABS to get the desired ASC/DESC.
SELECT * FROM theTable
ORDER BY SIGN(col) DESC, ABS(col)
EDIT
As Nahuel pointed out, the above will sort 0's to the middle between positive and negative. To instead group them with the positives, you can use a CASE instead (or, if your column is only integers, the slightly magical SIGN(col + 1))
SELECT * FROM theTable
ORDER BY
CASE WHEN col >= 0 THEN 1 ELSE 2 END,
ABS(col)

SELECT columnName1 FROM Tbl
WHERE columnName1 >= 0
ORDER BY columnName1 ASC
UNION
SELECT columnName1 FROM Tbl
WHERE columnName1 < 0
ORDER BY columnName1 DESC
Should work

Related

Query to Display records except Initial Record

For my project, i have a requirement where i have to display all the records in descending order except the first record. I am kind of messed up. Anyways, i have tried the following:
SELECT * FROM ins_nr nl WHERE nl.nl_status = '2' ORDER BY nl.nl_id DESC
Here, i have a table called ins_nr which will display all the records with status 2 and the id which is the primary key(unique). It is displaying in desc order perfectly.
I dont want the first record from the top alone. What should i do? How to modify the above query..?
Use OFFSET. Then you can skip 1 records and select the remaining ones until the end.
Example:
SELECT * FROM ins_nr nl WHERE nl.nl_status = '2'
ORDER BY nl.nl_id DESC LIMIT 99999999999 OFFSET 1;
OR ( You could also use a shorter syntax to achieve the same result: )
$sql = "SELECT * FROM table_name LIMIT 1, 999999999";
You can generate dynamic rownum and filter on it to omit the first row, e.g.:
SELECT *
FROM (
SELECT nl.*, #r := #r + 1 AS `rn`
FROM ins_nr nl, (SELECT #r := 0)
WHERE nl.nl_status = '2'
ORDER BY nl.nl_id DESC
) a
WHERE a.rn > 1;
Another way is to get the max id from subquery and put it in a where clausole
You are looking for the offset clause. This looks like:
SELECT *
FROM ins_nr nl
WHERE nl.nl_status = '2'
ORDER BY nl.nl_id DESC
LIMIT 999999999 OFFET 1;
Unfortunately, LIMIT is required. For this situation, it is traditional to just put in a very large number.
Also, if nl_status is numeric, then use nl.nl_status = 2. Don't compare strings to numbers.

Order an array with null values last [duplicate]

Currently I am doing a very basic OrderBy in my statement.
SELECT * FROM tablename WHERE visible=1 ORDER BY position ASC, id DESC
The problem with this is that NULL entries for 'position' are treated as 0. Therefore all entries with position as NULL appear before those with 1,2,3,4. eg:
NULL, NULL, NULL, 1, 2, 3, 4
Is there a way to achieve the following ordering:
1, 2, 3, 4, NULL, NULL, NULL.
MySQL has an undocumented syntax to sort nulls last. Place a minus sign (-) before the column name and switch the ASC to DESC:
SELECT * FROM tablename WHERE visible=1 ORDER BY -position DESC, id DESC
It is essentially the inverse of position DESC placing the NULL values last but otherwise the same as position ASC.
A good reference is here http://troels.arvin.dk/db/rdbms#select-order_by
I found this to be a good solution for the most part:
SELECT * FROM table ORDER BY ISNULL(field), field ASC;
NULL LAST
SELECT * FROM table_name ORDER BY id IS NULL, id ASC
Something like
SELECT * FROM tablename where visible=1 ORDER BY COALESCE(position, 999999999) ASC, id DESC
Replace 999999999 with what ever the max value for the field is
That's simple. You just need to order twice:
first step, order NULLs
second step, order your field.
SELECT * FROM table_name
ORDER BY ISNULL(field_name), field_name;
It works with any types, including JSON.
You can swap out instances of NULL with a different value to sort them first (like 0 or -1) or last (a large number or a letter)...
SELECT field1, IF(field2 IS NULL, 9999, field2) as ordered_field2
FROM tablename
WHERE visible = 1
ORDER BY ordered_field2 ASC, id DESC
Try using this query:
SELECT * FROM tablename
WHERE visible=1
ORDER BY
CASE WHEN position IS NULL THEN 1 ELSE 0 END ASC,id DESC
This works well for me as well.
ORDER BY ISNULL(field), field = 0 ASC;
Returns
1
2
3
0
0
null
null
You can coalesce your NULLs in the ORDER BY statement:
select * from tablename
where <conditions>
order by
coalesce(position, 0) ASC,
id DESC
If you want the NULLs to sort on the bottom, try coalesce(position, 100000). (Make the second number bigger than all of the other position's in the db.)
For a DATE column you can use:
NULLS last:
ORDER BY IFNULL(`myDate`, '9999-12-31') ASC
Blanks last:
ORDER BY IF(`myDate` = '', '9999-12-31', `myDate`) ASC
SELECT * FROM tablename WHERE visible=1 ORDER BY CASE WHEN `position` = 0 THEN 'a' END , position ASC
To achieve following result :
1, 2, 3, 4, NULL, NULL, NULL.
USE syntax, place -(minus sign) before field name and use inverse order_type(Like: If you want order by ASC order then use DESC or if you want DESC order then use ASC)
SELECT * FROM tablename WHERE visible=1 ORDER BY -position DESC
This is working fine:
SELECT * FROM tablename ORDER BY position = 0, position ASC;
position
1
2
3
0
0
Why don't you order by NULLS LAST?
SELECT *
FROM tablename
WHERE visible = 1
ORDER BY position ASC NULLS LAST, id DESC

Orderby MYSQL Syntax Wrong Data

I have a Table with a Column 'Rechnungnr' and 'Date'
Example 2016/204, 2016/202, 2016/100, 2015/12, 2016/231
and i need the last highest number. Here -> 2016/231.
SELECT * FROM TABLE Where YEAR(Date) = '2016' ORDER BY length(`Rechnungnr`) DESC LIMIT 1
But thats not working :(
Greetz, Malte
Use a combination of char_length() and the value of rechnungnr to get the max value this way:
SELECT * FROM TABLE
Where YEAR(Date) = 2016 ORDER BY char_length(`Rechnungnr`) DESC, `Rechnungnr` DESC LIMIT 1
char_length() will order the results by the number of characters within Rechnungnr field, and then within the equally long strings, we order by the value of the field itself.
Try using column name date surrounded by backtics
SELECT * FROM TABLE Where YEAR(`Date`) = '2016' ORDER BY length(`Rechnungnr`) DESC LIMIT 1
With your existing data set (if I understand the schema correctly) you can try something like this to get the day of year, cast it to an int and then sort on it:
SELECT *, CAST(RIGHT(LENGTH(`Rechnungnr`) - (INSTR(`Rechnungnr`, '/') + 1)) AS UNSIGNED) AS `DayOfYear` FROM TABLE Where YEAR(Date) = '2016' ORDER BY `DayOfYear` DESC LIMIT 1

Simplify CASE expression used multiple times

For readability, I would like to modify the below statement. Is there a way to extract the CASE statement, so I can use it multiple times without having to write it out every time?
select
mturk_worker.notes,
worker_id,
count(worker_id) answers,
count(episode_has_accepted_imdb_url) scored,
sum( case when isnull(imdb_url) and isnull(accepted_imdb_url) then 1
when imdb_url = accepted_imdb_url then 1
else 0 end ) correct,
100 * ( sum( case when isnull(imdb_url) and isnull(accepted_imdb_url) then 1
when imdb_url = accepted_imdb_url then 1
else 0 end)
/ count(episode_has_accepted_imdb_url) ) percentage
from
mturk_completion
inner join mturk_worker using (worker_id)
where
timestamp > '2015-02-01'
group by
worker_id
order by
percentage desc,
correct desc
You can actually eliminate the case statements. MySQL will interpret boolean expressions as integers in a numeric context (with 1 being true and 0 being false):
select mturk_worker.notes, worker_id, count(worker_id) answers,
count(episode_has_accepted_imdb_url) scored,
sum(imdb_url = accepted_imdb_url or imdb_url is null and accepted_idb_url is null) as correct,
(100 * sum(imdb_url = accepted_imdb_url or imdb_url is null and accepted_idb_url is null) / count(episode_has_accepted_imdb_url)
) as percentage
from mturk_completion inner join
mturk_worker
using (worker_id)
where timestamp > '2015-02-01'
group by worker_id
order by percentage desc, correct desc;
If you like, you can simplify it further by using the null-safe equals operator:
select mturk_worker.notes, worker_id, count(worker_id) answers,
count(episode_has_accepted_imdb_url) scored,
sum(imdb_url <=> accepted_imdb_url) as correct,
(100 * sum(imdb_url <=> accepted_imdb_url) / count(episode_has_accepted_imdb_url)
) as percentage
from mturk_completion inner join
mturk_worker
using (worker_id)
where timestamp > '2015-02-01'
group by worker_id
order by percentage desc, correct desc;
This isn't standard SQL, but it is perfectly fine in MySQL.
Otherwise, you would need to use a subquery, and there is additional overhead in MySQL associated with subqueries.

MySQL Orderby a number, Nulls last

Currently I am doing a very basic OrderBy in my statement.
SELECT * FROM tablename WHERE visible=1 ORDER BY position ASC, id DESC
The problem with this is that NULL entries for 'position' are treated as 0. Therefore all entries with position as NULL appear before those with 1,2,3,4. eg:
NULL, NULL, NULL, 1, 2, 3, 4
Is there a way to achieve the following ordering:
1, 2, 3, 4, NULL, NULL, NULL.
MySQL has an undocumented syntax to sort nulls last. Place a minus sign (-) before the column name and switch the ASC to DESC:
SELECT * FROM tablename WHERE visible=1 ORDER BY -position DESC, id DESC
It is essentially the inverse of position DESC placing the NULL values last but otherwise the same as position ASC.
A good reference is here http://troels.arvin.dk/db/rdbms#select-order_by
I found this to be a good solution for the most part:
SELECT * FROM table ORDER BY ISNULL(field), field ASC;
NULL LAST
SELECT * FROM table_name ORDER BY id IS NULL, id ASC
Something like
SELECT * FROM tablename where visible=1 ORDER BY COALESCE(position, 999999999) ASC, id DESC
Replace 999999999 with what ever the max value for the field is
That's simple. You just need to order twice:
first step, order NULLs
second step, order your field.
SELECT * FROM table_name
ORDER BY ISNULL(field_name), field_name;
It works with any types, including JSON.
You can swap out instances of NULL with a different value to sort them first (like 0 or -1) or last (a large number or a letter)...
SELECT field1, IF(field2 IS NULL, 9999, field2) as ordered_field2
FROM tablename
WHERE visible = 1
ORDER BY ordered_field2 ASC, id DESC
Try using this query:
SELECT * FROM tablename
WHERE visible=1
ORDER BY
CASE WHEN position IS NULL THEN 1 ELSE 0 END ASC,id DESC
This works well for me as well.
ORDER BY ISNULL(field), field = 0 ASC;
Returns
1
2
3
0
0
null
null
You can coalesce your NULLs in the ORDER BY statement:
select * from tablename
where <conditions>
order by
coalesce(position, 0) ASC,
id DESC
If you want the NULLs to sort on the bottom, try coalesce(position, 100000). (Make the second number bigger than all of the other position's in the db.)
For a DATE column you can use:
NULLS last:
ORDER BY IFNULL(`myDate`, '9999-12-31') ASC
Blanks last:
ORDER BY IF(`myDate` = '', '9999-12-31', `myDate`) ASC
SELECT * FROM tablename WHERE visible=1 ORDER BY CASE WHEN `position` = 0 THEN 'a' END , position ASC
To achieve following result :
1, 2, 3, 4, NULL, NULL, NULL.
USE syntax, place -(minus sign) before field name and use inverse order_type(Like: If you want order by ASC order then use DESC or if you want DESC order then use ASC)
SELECT * FROM tablename WHERE visible=1 ORDER BY -position DESC
This is working fine:
SELECT * FROM tablename ORDER BY position = 0, position ASC;
position
1
2
3
0
0
Why don't you order by NULLS LAST?
SELECT *
FROM tablename
WHERE visible = 1
ORDER BY position ASC NULLS LAST, id DESC