SQL Case - how to order by another field ASC - mysql

I have a SQL query that sorts a table for a local restaurant into categories, but after that I would like to sort alphabetically by title. The end result should sort the categories, and then the content is sorted alphabetically by the title field (like "ORDER BY category, title ASC", only the category gets sorted by case).
My query is
SELECT *
FROM menu
ORDER BY CASE WHEN category = 'Appetizers' THEN 1
WHEN category = 'Entrees' THEN 2
WHEN category = 'Desserts' THEN 3
WHEN category = 'Beverages' THEN 4
END
I tried adding ", title ASC" to each line, and after the END but it came up as an error. Can this be done at all?

It behaves like any other ORDER sorting
first it will sort by the CASE and then every entry with the same category by title
SELECT *
FROM menu
ORDER BY CASE WHEN category = 'Appetizers' THEN 1
WHEN category = 'Entrees' THEN 2
WHEN category = 'Desserts' THEN 3
WHEN category = 'Beverages' THEN 4
ELSE 5
END ASC, title ASC

Just need to add title in the ORDER BY clause after the CASE expression.This will sort the data by category based on the CASE and then the title within each category group.
Query
SELECT *
FROM menu
ORDER BY CASE WHEN category = 'Appetizers' THEN 1
WHEN category = 'Entrees' THEN 2
WHEN category = 'Desserts' THEN 3
WHEN category = 'Beverages' THEN 4
END, title;

Related

Union All with a particular value at first row

I'm using union all clause like
select * from products where id=1
union select * from products order by price desc
But as result i got the product with id 1 at the middle of the list as it makes a filter with price
How can i get the product with id 1 at the first row?
You seem to want a conditional sort rather than union:
select *
from products
order by case when id = 1 then 1 else 2 end, price desc
This puts first the row with id 1, followed by the rest of the records ordered by decreasing price.

How to keep mysql names together in ordered list

I have the following list of items
Category
OrderNum
Prerequisites
2
NULL
4
Prerequisites
6
Sign Off
8
Sign Off
10
I would like it to be ordered so that 'Prerequisites' is together and the NULL category appears after it, so that:
Category
OrderNum
Prerequisites
2
Prerequisites
6
NULL
4
Sign Off
8
Sign Off
10
Currently my SQL has the following order by:
ORDER BY OrderNum <> '' DESC, OrderNum
I've tried the following, however it puts NULL at the end.
ORDER BY COALESCE(Category,'') <> '' DESC, OrderNum <> '' DESC, OrderNum
I'm trying to achieve it so that the records with the same category are together in the recordset, the NULL item should appear before the 'Sign Off' category because the OrderNum of NULL is less than any of the 'Sign Off' records.
I'm not sure if that's possible in one query. Any help would be appreciated.
Thanks!
You can apply all the conditions that you want with a CASE expression:
SELECT * FROM tablename
ORDER BY CASE
WHEN Category = 'Prerequisites' THEN 1
WHEN Category IS NULL THEN 2
ELSE 3
END,
Category,
OrderNum;
or, if there are also empty strings in Category which you want sorted with the NULLs:
SELECT * FROM tablename
ORDER BY CASE
WHEN Category = 'Prerequisites' THEN 1
WHEN COALESCE(Category, '') = '' THEN 2
ELSE 3
END,
Category,
OrderNum;
or:
SELECT * FROM tablename
ORDER BY Category = 'Prerequisites' DESC,
Category IS NULL DESC, -- or: COALESCE(Category, '') = '' DESC,
Category,
OrderNum;
But, if what you want is to sort the rows by the minimum OrderNum of each Category use a correlated subquery:
SELECT t1.* FROM tablename t1
ORDER BY (SELECT MIN(t2.OrderNum) FROM tablename t2 WHERE t2.Category = t1.Category),
t1.OrderNum;
or, for MySql 8.0+ use MIN() window function:
SELECT * FROM tablename
ORDER BY MIN(OrderNum) OVER (PARTITION BY Category),
OrderNum;
See the demo.
If you want the NULL values right after Prerequisites, you can use PrerequisitesZ as the fallback for NULL values:
ORDER BY COALESCE(Category, 'PrerequisitesZ') DESC, OrderNum;
You can try using two conditions in the ORDER BY clause:
if Category has the value "Prerequisites", it should come first
otherwise order by the OrderNum value
Here's how you would do it:
SELECT *
FROM tab
ORDER BY IF(Category='Prerequisites', 0, 1),
OrderNum
Demo here.
Note: Actually you can play how much you want with the conditions in the ORDER BY clause, as it can accept most of MySQL constructs.

select rows mysql order by custom value From the bottom of the table to the top of the table

I want Last eight posts if productgroup='برنامه نویسی' And the results that they have subject="css" Have a higher priority
this is my code :
$query = "SELECT productcode FROM (SELECT * FROM product ORDER BY productcode DESC) secondTab
WHERE productgroup='برنامه نویسی' ORDER BY FIELD(subject,'css') DESC limit 8";
But get result From the top of the table to the bottom of the table:
6
7
8
10
14
20
34
2
The ORDER BY clause inside the subquery is useless.
Sort the results like this:
SELECT productcode
FROM product
WHERE productgroup = 'برنامه نویسی'
ORDER BY FIELD(subject,'css') DESC, productcode DESC
LIMIT 8
If you want product code 21 to be last, use two order by keys:
order by (productcode = 21) asc, -- put it last
productcode desc
MySQL treats boolean values as integers in a numeric context, with 0 for false and 1 for true. Hence, "false" is ordered (using ASC) before true values.

Add temp colunm to mysql query with value dependant on order clause

I have mutliple selects on my search collecting all my look_up_to_cat_id's each been ordered by relevance with this order clause.
WHEN '.$searchProperties['col'].' LIKE \''.$term.'\' THEN '.$c_0++.'
WHEN '.$searchProperties['col'].' LIKE \''.$term.'%\' THEN '.$c_20++.'
WHEN '.$searchProperties['col'].' LIKE \'%'.$term.'%\' THEN '.$c_40++;
My problem is when I start combining all my results, my ordering goes all messed up. I want to be able to add a column on to my query that will have one of the above numbers $c_0 or $c_20 or $c40 depending one which order clause applies to the result so that I can combine all the recordsets into an array and sort them correctly in the array using those numbers
This is one of my actual SQL statements to give you an idea.
SELECT `catelogue`.*,`release_date`.`RELEASE_DATE` FROM catelogue
LEFT JOIN `release_date` ON `catelogue`.`RELEASEDATE_ID` = `release_date`.`ID`
WHERE TITLE LIKE '%barbie%'
GROUP BY ID
ORDER BY
(CASE WHEN TITLE LIKE 'barbie' THEN 0
WHEN TITLE LIKE 'barbie%' THEN 200
WHEN TITLE LIKE '%barbie%' THEN 400
ELSE 600 END ),
( CASE WHEN TITLE LIKE 'barbie' THEN RELEASE_DATE
WHEN TITLE LIKE 'barbie%' THEN RELEASE_DATE
WHEN TITLE LIKE '%barbie%' THEN RELEASE_DATE END) desc,TITLE
So basically everything that matches 'barbie' will have 0 in the temp col then everything that matches 'barbie%' will have 200 and so on
I hope I have been clear enough
Just move the case statements into the select clause:
SELECT `catelogue`.*,`release_date`.`RELEASE_DATE`,
(CASE WHEN TITLE LIKE 'barbie' THEN 0
WHEN TITLE LIKE 'barbie%' THEN 200
WHEN TITLE LIKE '%barbie%' THEN 400
ELSE 600
END ) as order1,
FROM catelogue
LEFT JOIN `release_date` ON `catelogue`.`RELEASEDATE_ID` = `release_date`.`ID`
WHERE TITLE LIKE '%barbie%'
GROUP BY ID
ORDER BY
order1,
( CASE WHEN TITLE LIKE 'barbie' THEN RELEASE_DATE
WHEN TITLE LIKE 'barbie%' THEN RELEASE_DATE
WHEN TITLE LIKE '%barbie%' THEN RELEASE_DATE END) desc,TITLE;
You can now use the value in other queries.

Alternative to "IN" that works like "AND" instead of "OR"

From my understanding, IN works like this:
$arrayName = array(1, 2, 3);
SELECT *
FROM tableName
WHERE productID IN ($arrayName)
is the equivalent of:
SELECT *
FROM tableName
WHERE productID = 1 OR productID = 2 OR productID = 3
I'm wondering if there's a SQL function that works like IN but uses AND in place of OR to compare to an array. Something that would expand to this:
SELECT *
FROM tableName
WHERE productID = 1 AND productID = 2 AND productID = 3
Not that it's necessary, but for context I'm simply creating a sort list for some search results that are being populated on a PHP page via jQuery. I can do what I need with PHP, I'll simply create the query dynamically depending on what options the user has selected, but I'd rather use an intelligent SQL function if possible.
***EDIT: Thanks everyone for the help. I explained my problem very poorly and you were still able to sort it out, which I appreciate. I found that someone else had asked this question more eloquently and received an answer that I can use:
Is there something in MySQL like IN but which uses AND instead of OR?
I'm trying to figure out how to accept an answer and close this but I'm having a bit of trouble...
You cannot possibly do this,
SELECT *
FROM tableName
WHERE productID = 1 AND productID = 2 AND productID = 3
the condition will always returns false because a row can have only one value on its column, the alternative way to do this is by grouping the result, ex.
SELECT colName
FROM tableName
WHERE productID IN (1,2,3)
GROUP BY colName
HAVING COUNT(DISTINCT colName) = 3
by having a condition HAVING COUNT(DISTINCT colName) = 3, this means that the instance of a record must be equal to the total count of parameters supplied on IN clause.
As written, your query will produce no rows. It is not possible for productID in a row to be equal to both 1 and 2 at the same time.
You are probably looking for a group of rows that contain these three products. Say you want to find orders that have all three products. You can use something like:
select orderid
from orderlines ol
group by orderid
havnig max(case when ol.productid = 1 then 1 else 0 end) > 0 and
max(case when ol.productid = 2 then 1 else 0 end) > 0 and
max(case when ol.productid = 3 then 1 else 0 end) > 0
The GROUP BY with the HAVING clause will find orders where all three products are present.
SELECT orderid
FROM tableName
WHERE productID IN (1, 2, 3)
GROUP BY orderid
HAVING COUNT(DISTINCT productID) = 3 --this number must match the number of unique IDs in the IN clause