ORDER BY discrete values of text column on [My]SQL[ite] - mysql

I would like to sort the rows in a table based on an arbitrary ordering of a limited set of values of a text (or enum) column. For instance, if column "Classes" can have the values A, B, C, D, I would like to be able to sort rows by A > C > B > D or by some other combination, and not just alphabetically or by the native order of the enum. Is that even possible?
Ideally, I would like a solution that works on SQLite, but a MySQL one would also be useful. Many thanks!

ORDER BY field(column, 'A', 'C', 'B', 'D')
FIELD function in MySQL docs

If mySQL and sqlite sllow the use of CASE in ORDER BY clauses (MSSQL does and I see no reason why other systems won't), you could use something like:
ORDER BY CASE
WHEN classes ='A' THEN 1
WHEN classes ='C' THEN 2
WHEN classes ='B' THEN 3
WHEN classes ='D' THEN 4
ELSE 5
END CASE
If the column can contain more than one of the options in any particular order you could also do:
ORDER BY CASE
WHEN classes LIKE '%A%' THEN 1
WHEN classes LIKE '%C%' THEN 2
WHEN classes LIKE '%B%' THEN 3
WHEN classes LIKE '%D%' THEN 4
ELSE 5
END CASE
though overloading a field like that is not a normal form and is generally not recommended.

Yet another variant - add a new (temporary?) table such as
class | rank
A | 1
B | 2
C | 3
D | 4
Then you can join the table by the class column and order by the rank.

Related

SQL query statement Self Join?

new to SQL.
I have the following set of data
A X Y Z
1 Wind 1 1
2 Wind 2 1
3 Hail 1 1
4 Flood 1 1
4 Rain 1 1
4 Fire 1 1
I would like to select all distinct 'A' fields where for all rows that contain A have flood and rain.
So in this example, the query would return only the number 4 since for the set of all rows that contain A = 4 we have Flood and Rain.
I need the values of A where for a given value 'a' in A, there exists rows with 'a' that must contain all of the following fields provided (in the example Flood and Rain).
Please let me know if you need further clarification.
I need the values of A where for a given value 'a' in A, there exists rows with 'a' that must contain all of the following fields provided (in the example Flood and Rain).
You can use aggregation, and filter with a having clause:
select a
from mytable t
where x in ('Flood', 'Rain') -- either one or the other
having count(*) = 2 -- both match
If tuples (a, x) tuples are not unique, then you want having count(distinct x) = 2 instead.
You Shooud use count(distinct X) group by A and having
count(distinct...) avoid situation where you have two time the same value for X
select A
from my_table
WHERE x in ('Flood', 'Rain')
group A
having count(distinct X) = 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 ;

How to define a custom ORDER BY order in mySQL

In MySQL how do I define a custom sorting order.
To try to explain what I want consider this table:
ID Language Text
0 ENU a
0 JPN b
0 DAN c
1 ENU d
1 JPN e
1 DAN f
2 etc...
here I want to return all rows sorted by Language and ascending ID so that Language = ENU comes first, then JPN and lastly DAN.
The result should be: a,d,b,e,c,f etc.
Is this even possible?
MySQL has a handy function called FIELD() which is excellent for tasks like this.
ORDER BY FIELD(Language,'ENU','JPN','DAN'), ID
Note however, that
It makes your SQL less portable, as other DBMSs might not have such function
When your list of languages (or other values to sort by) gets much longer, it's better to have a separate table with sortorder column for them, and join it to your queries for ordering.
If those are the only three values, then you can use a CASE expression:
ORDER BY `ID`,
CASE `Language`
WHEN 'ENU' THEN 1
WHEN 'JPN' THEN 2
WHEN 'DAN' THEN 3
END
(If there could be other values, then you may want to add some extra logic to keep the ordering consistent; for example, you might add ELSE 4 to that CASE expression, and then order by Language itself as the third ordering criterion:
ORDER BY `ID`,
CASE `Language`
WHEN 'ENU' THEN 1
WHEN 'JPN' THEN 2
WHEN 'DAN' THEN 3
ELSE 4
END,
`Language`
)
You have a couple of options offhand, the first is to change Language to be ENUM (assuming this is possible, and you only expect a few variations)
If you specify it as ENUM('ENU','JPN','DAN') then ORDER Language ASC will order in the order you specify.
The second will involve a case somewhere, i.e.
SELECT * FROM table
ORDER BY CASE Language
WHEN 'ENU' THEN 3
WHEN 'JPN' THEN 2
WHEN 'DAN' THEN 1
ELSE 0
END DESC, ID ASC
Performance-wise the ENUM method will return faster results, but be more hassle if you need to add more languages. A third option would be to add a normalisation table for the Languages however that may be overkill in this instance.
For Yii2 framework we can achieve by following way
Project::find()
->orderBy([
new Expression('FIELD(pid_is_t_m,2,0,1)'),
'task_last_work'=> SORT_ASC
])->all();

MySQL Selecting Something with Array Information

Is there a way to do something like this?
SELECT * FROM tablename WHERE x CONTAINS "1"
Basically, I want to select data from the database where x contains a specific number. The thing is, the x column in any row could contain "1, 2, 3" and I want to select all those that contain 1, specifically 1, not 11 or anything that contains 1, but specifically a 1.
Here's an example:
id title x
-------------------
1 row1 1,22,3
2 row2 1,5
3 row3 5,91
4 row4 70
And I want my query to return rows 1 and 2. I don't want row 3, as the 1 is inside the number 91. I don't want row 4 because there's no 1 there either.
You can use the FIND_IN_SET function like so:
SELECT * FROM tablename WHERE FIND_IN_SET('1', x)
This will also get optimised to use bit arithmetic if you are calling it on a SET type.
You can try this:
SELECT * FROM tablename WHERE x REGEXP "(^|,)1(,|$)"
Ideally you'd normalize your 'x' column out to a separate table.
But... you could also hack it like this:
SELECT * FROM tablename WHERE x LIKE '%,1' OR x LIKE '1,%' OR x LIKE '%,1,%'
This basically just handles the three different cases where the "1" is the first, last or a middle element in your list. (note if you've got a space after your commas you'd change the last part to '%, 1,%'
EDIT: Actually Dmitriy's REGEXP is nicer, and a'r's FIND_IN_SET looks ideal.

mysql select update

Got this:
Table a
ID RelatedBs
1 NULL
2 NULL
Table b
AID ID
1 1
1 2
1 3
2 4
2 5
2 6
Need Table a to have a comma separated list as given in table b. And then table b will become obsolete:
Table a
ID RelatedBs
1 1,2,3
2 4,5,6
This does not rund through all records, but just ad one 'b' to 'table a'
UPDATE a, b
SET relatedbs = CONCAT(relatedbs,',',b.id)
WHERE a.id = b.aid
UPDATE: Thanks, 3 correct answers (marked oldest as answer)! GROUP_CONCAT is the one to use. No need to insert commas between the ids using relatedids = CONCAT(relatedids,',',next_id) that is done automatic by GROUP_CONCAT.
You'll have to use the mysql group_concat function in order to achieve this: http://dev.mysql.com/doc/refman/5.1/en/group-by-functions.html#function_group-concat
Look into GROUP_CONCAT(expr)
mysql> SELECT student_name,
-> GROUP_CONCAT(DISTINCT test_score
-> ORDER BY test_score DESC SEPARATOR " ")
-> FROM student
-> GROUP BY student_name;
You can't do that in standard SQL. You could write a stored procedure to do that. I had a similar problem, but I was using PostgreSQL so I was able to resolve it by writing a custom aggregate function so that you can do queries like
select aid, concat(id)
from b group by
aid
Update: MySQL has a group_concat aggregate function so you can do something like
SELECT id,GROUP_CONCAT(client_id) FROM services WHERE id = 3 GROUP BY id
as outlined here.