Selecting a specific row followed by an order by? - mysql

I have this data
names
============
All
Brian
Carey
Heather
Robert
Zach
_Immediate
This is when they are selected ORDER BY name. I would like to craft a statement so that the _Immediate appears at top like
names
============
_Immediate
All
Brian
Carey
Heather
Robert
Zach
If it matters/helps, _Immediate has the absolute lowest ID in the list. How can I do this? Is a UNION the only way?

You can specify the ORDER BY using a CASE expression:
ORDER BY CASE
WHEN names = '_Immediate' THEN 0
ELSE 1
END
, names

In MySQL, I think the simplest method is:
order by (name = '_Immediate') desc, name
MySQL treats a boolean as an integer, with "1" for true and "0" for false. The desc is so the "1" is before the "0".

You can try below -
select * from tablename
order by case when names='_Immediate' then 0 else 1 end, names

Related

MySQL - Match certain IDs, but only those IDs

I have a table like so:
id_type id_option
"1" "1"
"1" "5"
"2" "1"
"2" "5"
"2" "8"
I am trying to write a query that given a list of option IDs finds the "type" that matches the list, but only those ID's
For example, if given 1 and 5 as options, it should return the type 1 but only the type 1 as the 8 required to match type 2 is not present.
I have tried the following:
SELECT *
FROM my_table
WHERE id_option IN (1, 5)
GROUP BY id_type
HAVING COUNT(DISTINCT id_option) = 2
This returns both "types" - I had hoped that the COUNT restriction of 2 would have helped but I now understand why it doesn't, but I can't think of a clever way to limit this.
I could just pull the first record as typically the types with less options are saved first but I don't think I can rely on this 100%
Thank you for your time
Here's a solution:
SELECT *
FROM my_table
GROUP BY id_type
HAVING SUM(id_option IN (1,5)) = COUNT(*)
It relies on a trick specific to MySQL: boolean true is literally the integer 1. So you can use SUM() to count the rows where a condition is true, but putting a boolean expression inside SUM().
For folks reading this who use other databases besides MySQL, you'd have to use an expression to convert the boolean condition to the integer 1:
HAVING SUM(CASE WHEN id_option IN (1,5) THEN 1 ELSE 0 END) = COUNT(*)
In this case, let all rows become part of the groups. That is, do not use a WHERE clause to restrict the query to rows where the id_option is 1 or 5. Then count the total rows in the group, and "count" (i.e. use the SUM() trick) the rows where the id_options is 1 or 5. Comparing these counts will be equal if there are no id_options values besides 1 or 5.
If you also want to make sure that both 1 and 5 are found, you need another condition:
SELECT *
FROM my_table
GROUP BY id_type
HAVING SUM(id_option IN (1,5)) = COUNT(*)
AND COUNT(DISTINCT CASE WHEN id_option IN (1,5) THEN id_option END) = 2
The CASE expression will return 1 or 5, or if there are any other values, those are converted to NULL. The COUNT() function ignores NULLs.
If you can pass the options as a sorted comma separated list string, then use GROUP_CONCAT():
SELECT id_type
FROM my_table
GROUP BY id_type
HAVING GROUP_CONCAT(id_option ORDER BY id_option) = '1,5'
If there are duplicate options for each type, use DISTINCT:
HAVING GROUP_CONCAT(DISTINCT id_option ORDER BY id_option) = '1,5'
While I can't comment yet, here's a tiny adjustment to Bill Karwin's last example (in the accepted solution):
SELECT *
FROM my_table
GROUP BY id_type
HAVING SUM(id_option IN (1,5)) = COUNT(*)
AND COUNT(DISTINCT id_option) = 2

Sort MySQL rows by column, but not alphabetically

Sorry if the title is a bit ambiguous and reminiscent of other semi-related questions), the issue is in fact quite simple.
I have a VARCHAR column which can have 1-character values such as M,G,D and S. If I sort the results alphabetically, in this example it will show them in the order: D-G-M-S. However, I need to display the rows in the following order:
G-D-M-S
Is there a way to accomplish this within the query? I know I can custom-sort the results in PHP, but I'd rather do it within the query if possible. For this example, I just need to switch the order of "G" and "D" in the results, and the solution to that simplistic problem will suffice for any answers.
You can write your custom case statement:
Select *
from your_table
order by
case your_column
when 'G' then 1
when 'D' then 2
when 'M' then 3
when 'S' then 4
end
Also, another solution, is to change collation at physical level:
Change default Sorting by Adding a Simple Collation to an 8-Bit Character Set
What I would do is define a temp or permanent table with 2 columns :
letter | ordernum
-------------------
G | 1
D | 2
M | 3
S | 4
Then you join your exiting table to that new one on the field "letter", and use the new table "ordernum" field to do the sort...
SELECT
if(columnname='G',1,
if(columnname='D',2,
if(columnname='M',3,
if(columnname='S',4,0
)))) SortOrder
FROM tablename
ORDER BY
SortOrder ASC
Select col from table
order by case when col = 'G' then 1
when col = 'D' then 2
when col = 'M' then 3
case when col = 'S' then 4 else 5 end ;

Append blank results to end in alphabetical order

I would like to return a list of items by alphabetical order, but have the "empty" results append to the end as opposed to appearing at the beginning. Is there a way to do this using the MySQL ORDER statement, or perhaps another way?
SELECT * FROM persons WHERE status = 'active' ORDER BY lastName;
What I get:
Jason
Peter
Frank Asimov
Reda Banks
Scott Sorrel
What I want:
Frank Asimov
Reda Banks
Scott Sorrel
Jason
Peter
SELECT * FROM persons WHERE status = 'active'
ORDER BY case when ifnull(lastName,'') = '' then 1 else 0 end, lastname
You can do it using the FIELD statement. It goes something like that:
SELECT [...] ORDER BY FIELD(lastName, '') DESC
This will either append all the empty-string lastnames to the end. If instead of empty strings, you have NULL on your database:
SELECT [...] ORDER BY FIELD(lastName, NULL) DESC;
I believe all you need is to ORDER BY the firstName:
SELECT * FROM persons WHERE status = 'active' ORDER BY lastName, firstName

How to use GROUP BY to retrieve a result set with priority on alphabeticization for CASE field?

In a previous question I asked, someone suggested the MAX(value) syntax to prioritize on alphbetization
How to use GROUP BY to retrieve a result set with priority on alphabeticization
However I'm dealing with the CASE statement and using MAX(CASE statement) is syntactically incorrect.
SELECT id,
CASE
WHEN filename LIKE '%.mp3' THEN 'song'
ELSE 'other' END as type
FROM filenames
1 song
2 song
2 other
3 other
3 song
SELECT id,
CASE
WHEN filename LIKE '%.mp3' THEN 'song'
ELSE 'other' END as type
FROM filenames
GROUP BY id;
1 song
2 song
3 other
How would I prioritize the type field for those which come alphabetically last? Ex. the result set should be
1 song
2 song
3 song
I'd like to avoid nested statements if possible. Can this be done with the MAX(type) syntax?
You can use following
SELECT id,
CASE
WHEN filename LIKE '%.mp3' THEN 'song'
ELSE 'other' END as type
FROM filenames
GROUP BY id DESC;
DESC will give you descending order

Mysql: Order by like?

assume that we are performing search using keywords: keyword1, keyword2, keyword3
there are records in database with column "name":
1: John Doe
2: Samuel Doe
3: John Smith
4: Anna Smith
now Query:
SELECT * FROM users WHERE (name LIKE "%John%" OR name LIKE "%Doe%")
it will select records: 1,2,3 (in this order)
but i want to order it by keyword
in example keyword1=John, keyword2=Doe
so it should be listed by keywords: 1,3,2 (because i want to perform search for "Doe" after searching for "John")
I was thinking about SELECT DISTINCT FROM (...... UNION .....)
but it will be much easier to order it somehow in another way (real query is really long)
are there any tricks to create such order?
order by case
when name LIKE "%John%" then 1
when name LIKE "%Doe%" then 2
else 3
end
To build on RedFilter's answer, you could make the rows that have both keywords to be at the top:
order by case
when (name LIKE "%John%" and name LIKE "%Doe%") then 1
when name LIKE "%John%" then 2
when name LIKE "%Doe%" then 3
end
Read up on Boolean Fulltext Searches, with which you can do ordering.
SELECT *
from
(
SELECT u.*, 1 OrderNum
FROM users
WHERE (name LIKE "%John%")
UNION
SELECT u.*, 2 OrderNum
FROM users
WHERE (name LIKE "%Doe%")
)
Order by OrderNum
My example will Order all of the John's Alphabetically followed by the Doe's.
ORDER BY CASE
WHEN name LIKE "John%Doe" THEN CONCAT('a',name)
WHEN name LIKE "John%" THEN CONCAT('b',name)
WHEN name LIKE "%Doe" THEN CONCAT('c',name)
ELSE name
END