Mysql order by specific IDs first but still alphabetically - mysql

Is there a way I can get specific IDs at the top, but sorted alphabetically by title, followed by the rest of the records also sorted alphabetically by title?
What I have right now:
SELECT * FROM table ORDER BY FIELD(ID,2,3) DESC, title ASC
Example:
1 Lisa
2 Hannah
3 Adam
4 Brian
Should be sorted
3 Adam (because Adam is before Hannah)
2 Hannah
4 Brian (because Brian is before Lisa)
1 Lisa

select * from table
order by
case when id in (2,3)
then 0
else 1 end asc,
title asc

You would need a use a CASE statement that generated different values for each group that you wanted and then order by the case statement and then by the name

From you smal sample data you can use a CASE WHEN and ORDER which fields should be at the start, the second order is name in my case
CREATE TABLE tab1
(`id` int, `name` varchar(6))
;
INSERT INTO tab1
(`id`, `name`)
VALUES
(1, 'Lisa'),
(2, 'Hannah'),
(3, 'Adam'),
(4, 'Brian')
;
SELECT * FROM tab1 ORDER BY
CASE WHEN FIELD(ID,2,3) THEN 1 ELSE 2 END ASC,name ASC
#, title ASC
id | name
-: | :-----
3 | Adam
2 | Hannah
4 | Brian
1 | Lisa
db<>fiddle here

Related

How could I map a list including fields that are not found in a table?

It's my first time to use sql in practice, and I've met with such a situation in my .net core project:
I have a table now like this:
name:string
age:int
ticketType:enum
Jack
20
0
Anna
16
1
Tom
30
2
And I have a list of name = ["Jack", "George", "William"]
What I need is a table that contains both persons included with certain values and those excluded with default values like:
name:string
age:string
ticket:string
Jack
20 years
adult
George
Not found
Not found
William
Not found
Not found
How could I do this with sql?
Thanks in advance.
You can use a left join, but you need a list of the values you care about:
select name, t.age, t.tickettype
from (select 'Jack' as name union all
select 'George' union all
select 'William'
) n left join
t
using (name);
Note that this represents the "not found" value using NULL. This is the typical method in SQL. If you want a string, I would suggest that you do that in your application layer, because int and enum cannot represent an arbitrary string value.
The texdt you have to adapt to your needs
CREATE TABLE users
(`nameg` varchar(4), `age` int, `ticketType` int)
;
INSERT INTO users
(`nameg`, `age`, `ticketType`)
VALUES
('Jack', 20, 0),
('Anna', 16, 1),
('Tom', 30, 2)
;
SELECT t1.name,IFNULL(CONCAT (`age`, ' years'),'Not Found') age
, CASE `ticketType`WHEN
0 THen 'adult'
WHEN 1 THEn 'teenager'
WHEN 2 THEN'elserly'
ELSE 'NOT Found' END "type"
FROM (SELECT "Jack" as name UNION SELECT "George" UNION SELECT "William") t1
LEFT JOIN users u ON u.nameg = t1.name
name | age | type
:------ | :-------- | :--------
Jack | 20 years | adult
George | Not Found | NOT Found
William | Not Found | NOT Found
db<>fiddle here

Ignore Insertion if select subquery return null - Mysql

user
user_id | name
1 | John
2 | Matt
food
food_id | food_name
1 | A
2 | B
fav_food
user_id(-> user) | food_id(->food)
2 | 1
My insertion query:
INSERT INTO `fav_food`(user_id,food_id) VALUES(?,(SELECT id from `food` where food_name=?))
When the SELECT id from food where food_name=? subquery returns null insertion fails with an error which should be.
My question is, How can I ignore the insertion only when the subquery returns null or no rows? Thanks
With EXISTS:
INSERT INTO fav_food (user_id, food_id)
SELECT ?, (SELECT food_id FROM food WHERE food_name = ?)
WHERE EXISTS (SELECT 1 FROM food WHERE food_name = ?)
See the demo
You can try this:
INSERT INTO `fav_food`(user_id,food_id) VALUES(?,(SELECT id from `food` where food_name=? AND food_name IS NOT NULL))
From what I've tried before, you can do that by using an if statement in a stored procedure, the code might look something like the following:
if exists (SELECT id from `food` where food_name=?) then
INSERT INTO `fav_food`(user_id,food_id) VALUES(?,(SELECT id from `food` where food_name=?))
end if;

Kindly explain clearly the CTE Query?

I saw
WITH tblTemp as
(
SELECT ROW_NUMBER() Over(PARTITION BY Name,Department ORDER BY Name) As RowNumber, *
FROM <table_name>
)
DELETE FROM tblTemp where RowNumber > 1
This query for deleting duplicate rows, but I can't understand the Query. Could you please explain clearly?
The most instructive thing for you to do would be to select from the CTE:
SELECT *
FROM tblTemp
ORDER BY Department, Name;
Off the top of my head, you might see a result set looking like this:
Name | Department | RowNumber
Jon Skeet | Software | 1
Gordon Linoff | Database | 1
Gordon Linoff | Database | 2
The (Gordon Linoff, Database) record appears in duplicate, so there is a row number value in the second record which is greater than 1. Your delete logic would remove this duplicate, but would not affect the (Jon Skeet, Software) record, which has no duplicate.
The common table expression is locating duplicate rows, then the delete query that follows removes all but one row if there are duplicates.
SELECT
ROW_NUMBER() Over(PARTITION BY Name,Department ORDER BY Name) As RowNumber
,*
FROM <table_name>
In the over() clause the partition and order by defines where numbering starts at 1, then within each partition each extra row gets a larger row number. Hence when [RowNumber] = 1 you have a unique set of rows for name and department.
see: Over() and row_number()
Demonstration
CREATE TABLE mytable(
name VARCHAR(6) NOT NULL
,department VARCHAR(11) NOT NULL
);
INSERT INTO mytable(name,department) VALUES ('fred','sales');
INSERT INTO mytable(name,department) VALUES ('fred','sales');
INSERT INTO mytable(name,department) VALUES ('barney','admin');
INSERT INTO mytable(name,department) VALUES ('barney','admin');
INSERT INTO mytable(name,department) VALUES ('wilma','engineering');
WITH tblTemp as
(
SELECT ROW_NUMBER() Over(PARTITION BY Name,Department ORDER BY Name) As RowNumber, *
FROM mytable
)
DELETE FROM tblTemp where RowNumber > 1
;
select
*
from mytable
;
+---+--------+-------------+
| | name | department |
+---+--------+-------------+
| 1 | fred | sales |
| 2 | barney | admin |
| 3 | wilma | engineering |
+---+--------+-------------+

MySQL - How to get the next row

So I have a student_profiles table and ranks table, I want to get the next rank based on the student rank. For example, I have rank 5 then the next rank will be rank 6. So this is my rank structure.
RANKS TABLE:
SELECT * FROM RANKS WHERE style_id = 1"
id style_id level name type primary_colour secondary_colour
1 1 1 Newbie double #4e90b2 #3aad04
22 1 2 Normal solid #fba729 NULL
31 1 3 Expert solid #4e805b NULL
and this is STUDENT_PROFILES TABLE
id | student_id | rank_id
------------------------------------
1 | 1 | 36
2 | 4 | 22
3 | 7 | 10
so all I have a variable is student_id, rank_id & style_id
so for example, I have this value student_id = 4, rank_id = 22 & style_id = 1
It should return
id style_id level name type primary_colour secondary_colour
31 | 1 | 3 | Expert | Solid | #4e805b | NULL
If you just want to get the second row:
Do it like this:
select * from
(select * from table order by id asc limit 2) as a order by id desc limit 1
Any query structure it will work as you need second row if you follow that script.
Try with that:
SELECT * FROM `ranks` WHERE `level` > (SELECT `level` FROM `ranks` WHERE `id` = rank_id) LIMIT 1
But I think it isn't very effective solution.
One option for getting the next highest level in the RANKS table is to self-join this table on the level column, order ascending, and retain the very first record only.
SELECT r2.*
FROM RANKS r1
INNER JOIN
STUDENT_PROFILES s1
ON r1.id = s1.rank_id
INNER JOIN
RANKS r2
ON r2.level > r1.level
ORDER BY r2.level
LIMIT 1
Demo here:
SQLFiddle
Note: If RANKS has duplicate levels, and you want the next level with regard to cardinality (i.e. you don't want a duplicate equal level returned), then my query could be slightly modified to filter out such duplicates.

Sorting MYSQL Tag table

just wondering if it is possible to get the top 10 COUNT results and ordering by COUNT and alphabetically?
I have the following tables,
tags
-------
id | title
.
tagged
------
tag_id | post_id
And the following SQL query
SELECT tag.*, COUNT(td.tag_ID) AS tagcount
FROM Tagged td
LEFT JOIN Tags tag ON td.tag_ID = tag.tag_ID
GROUP BY td.tag_ID
ORDER BY tagcount DESC, tag.tag_Title ASC
Any ideas?
Thanks in advance
Edit
Sorry if I didnt explain it properly.
The query works and I didnt add LIMIT 10 due to wanting to see the entire result set first.
The query I have works, however at the following example result
tag_ID tag_Title tagcount
1 Science 3
3 Chemistry 2
4 Misc 1
5 Maths 1
2 Sport 1
I would want Chemistry to come above Science though.
i.e. top ten highest counts.. sorted alphabetically
Result
Thanks to you both.. Daniel and Sled.
Here is a working example
(
SELECT t.*, COUNT(*) AS tagcount
FROM tagged td
LEFT JOIN tags t ON (t.id = td.tag_id)
GROUP BY td.tag_id
ORDER BY tagcount DESC, t.title ASC
LIMIT 3
) ORDER BY title ASC;
UPDATE:
Further to the new comment below:
(
SELECT t.*, COUNT(*) AS tagcount
FROM tagged td
LEFT JOIN tags t ON (t.id = td.tag_id)
GROUP BY td.tag_id
ORDER BY tagcount DESC, t.title ASC
LIMIT 3
) ORDER BY title ASC;
Result:
+------+------------+----------+
| id | title | tagcount |
+------+------------+----------+
| 3 | javascript | 2 |
| 1 | mysql | 2 |
| 2 | php | 3 |
+------+------------+----------+
3 rows in set (0.00 sec)
Simply change the LIMIT 3 to LIMIT 10 to get the top 10 instead of the top 3.
Previous Answer:
Why don't you add a LIMIT 10 to your query?
SELECT t.*, COUNT(*) AS tagcount
FROM tagged td
LEFT JOIN tags t ON (t.id = td.tag_id)
GROUP BY td.tag_id
ORDER BY tagcount DESC, t.title ASC
LIMIT 10;
Test case:
CREATE TABLE tags (id int, title varchar(20));
CREATE TABLE tagged (tag_id int, post_id int);
INSERT INTO tags VALUES (1, 'mysql');
INSERT INTO tags VALUES (2, 'php');
INSERT INTO tags VALUES (3, 'javascript');
INSERT INTO tags VALUES (4, 'c');
INSERT INTO tagged VALUES (1, 1);
INSERT INTO tagged VALUES (2, 1);
INSERT INTO tagged VALUES (1, 2);
INSERT INTO tagged VALUES (2, 2);
INSERT INTO tagged VALUES (3, 3);
INSERT INTO tagged VALUES (2, 4);
INSERT INTO tagged VALUES (3, 4);
INSERT INTO tagged VALUES (4, 5);
Result (using LIMIT 3):
+------+------------+----------+
| id | title | tagcount |
+------+------------+----------+
| 2 | php | 3 |
| 3 | javascript | 2 |
| 1 | mysql | 2 |
+------+------------+----------+
3 rows in set (0.00 sec)
Note how the [c] tag fell out of the top 3 results, and rows are ordered alphabetically in case of a tie.
Does the query work? If yes, you could use LIMIT 0, 10 to get only the top 10 rows.
SELECT tag.*, COUNT(td.tag_ID) AS tagcount
FROM Tagged td
LEFT JOIN gen_Tags tag ON td.tag_ID = tag.tag_ID
GROUP BY td.tag_ID
ORDER BY tagcount DESC, tag.tag_Title ASC LIMIT 0, 10
Another thing you might be interested in, is ranking. See here: http://www.fromdual.com/ranking-mysql-results
Edit
Maybe a subquery does what you want:
SELECT list.* FROM (
SELECT tag.*, COUNT(td.tag_ID) AS tagcount,
FROM Tagged td
LEFT JOIN gen_Tags tag ON td.tag_ID = tag.tag_ID
GROUP BY td.tag_ID
ORDER BY tagcount DESC LIMIT 0, 10
) AS list ORDER BY list.tag_Title ASC, list.tagcount DESC