Issue ordering columns by the first letter in blank columns - mysql

Here is my tables
|users|
|id| |lastname1| |lastname2| |name| |company_name|
1 Messi Ramirez Lionel
2 Gates Bush Bill
3 Klose Kazer Miroslav
4 Ozil Demon Mezut
5 Facebook
6 GMAIL
7 MYSPACE
8 Twitter
I'm trying to order company_name like a lastname1.
Some friends gave me this code but is not working with blank values just with NULL values:
select * from users
order by COALESCE(lastname1,company_name),lastname2,name ASC;
I should have this answer
Note: the first letter of "facebook" is F and "Gates" is G so it continues with the next letter.
5 Facebook
2 Gates Bush Bill
6 GMAIL
3 Klose Kazer Miroslav
1 Messi Ramirez Lionel
7 MYSPACE
4 Ozil Demon Mezut
8 Twitter
Please somebody can help me?

Use coalesce():
order by coalesce(lastname1, company_name)
I'm not sure what the other columns are contributing to the order by so I removed them.
EDIT:
If the values are blank or spaces and not NULL, then use case:
order by (case when trim(lastname1) = '' or lastname1 is null then company_name
else lastname1
end)

You could do this with this query:
select * from users
order by COALESCE(lastname1,company_name),lastname2,name ASC;
COALESCE takes the first non null element of it's list.
DEMO
If as in the modified question empty strings should be considered equally to NULL then you could do this with
select * from users
order by
CASE
WHEN TRIM(lastname1) = '' THEN company_name
WHEN lastname1 IS NULL THEN company_name
ELSE lastname1
END;
Demo

Related

Finding rows which match and blanks

I have a table of users and a table of electronic signatures - I want to be able to show for a given document who has signed and who has not.
Lets say we have employees:
EID Name
1 Bob
2 Tom
3 Fred
signatures:
EID Document Signature
1 1 Bob
1 2 Bob
1 3 Bob
2 1 Tom
3 2 Fred
My issue is that I can get this to work fine for document 4 - as no one has signed I can look where the document is null
However, if I look for document 2, for example, then I am currently getting employees missed off the list
For document 2 I would want to see
EID Signature
1 Bob
2
3 Fred
For document 4 I would want to see:
EID Signature
1
2
3
and for document 1:
EID Signature
1 Bob
2 Tom
3
The query I have tried to use is:
SELECT e.eid, s.signature
from employees e
left join signatures s on e.eid=s.eid
where s.document=? or s.document IS NULL group by e.eid
There are multiple issues:
Whenever using Left Join, any Where conditions on the right-side tables, should be put in the On clause. Otherwise, it will filter your result-set, even if there is no matching row (losing the purpose of Left Join)/
To compare null values, we use IS NULL. = null does not work. In this case, if we shift the conditions to On clause, we don't need to check for null values either.
Group By usage is invalid and really not required. When using Group By, only aggregated columns or the columns specified in Group By should come in Select. Refer: https://stackoverflow.com/a/41887524/2469308
Try the following:
SELECT e.eid, s.signature
FROM employees e
LEFT JOIN signatures s
ON e.eid=s.eid AND
s.document = ?

Limit selected results by unique selected IDs when using left joins

I have a table users and some other tables like images and products
Table users:
user_id user_name
1 andrew
2 lutz
3 sophie
4 michael
5 peter
6 oscor
7 anton
8 billy
9 henry
10 jon
Tables images:
user_id img_type img_url
1 0 url1
1 1 url4
2 0 url5
7 0 url7
8 0 url8
9 1 url9
Table Products
user_id prod_id
1 5
1 55
2 555
8 5555
9 5
9 55
I use this kind of SELECT:
SELECT * FROM
(SELECT user.user_id,user.user_name, img.img_type, prod.prod_id FROM
users
LEFT JOIN images img ON img.user_id = users.user_id
LEFT JOIN products prod ON prod.user_id = users.user_id
WHERE user.user_id <= 5) AS users
ORDER BY user.user_id ASC
The result should be the following output. Due to performance improvements, I use ORDER BY and an inner select. If I put a LIMIT 5 within the inner or outer select, things won't work. MySQL will hard LIMIT the results to 5. However I need the LIMIT of 5 (pagination) found unique user_id results which would lead to 9 in this case.
Can I use maybe an if-statement to push an array with found user_id and break/finish up the select when the array consist of 5 UIDs? Or can I modify somehow the select?
user_id user_name img_type prod_id
1 andrew 0 5
1 andrew 1 5
1 andrew 0 55
1 andrew 1 55
2 lutz 0 5
2 lutz 0 55
3 sophie null null
4 michael null null
5 peter null null
results: 9
LIMIT 5 and user_id <= 5 do not necessarily give you the same results. One reason: There are multiple rows (after the JOINs) for user_id = 1. This is because there can be multiple images and/or multiple products for a given 'user'.
So, first decide which you want.
LIMIT without ORDER BY gives you an arbitrary set of rows. (Yeah, it is somewhat predictable, but you should not depend on it.)
ORDER BY + LIMIT usually implies gathering all the potentially relevant rows, sorting them, then doing the "limit". There are sometimes ways around this sluggishness.
LEFT leads to the NULLs you got; did you want that?
What do you want pagination to do if you are displaying 5 items per page, but user 1 has 6 images? You need to think about this edge case before we can help you with a solution. Maybe you want all of user 1 on a page, even if it exceeds 5? Maybe you want to break in the middle of '1'; but then we need an unambiguous way to know where to continue from for the next page.
Probably any viable solution will not use nested SELECTs. As you are finding out, it leads to "errors". Think of it this way: First find all the rows you need to display on all the pages, then carve out 5 for the current page.
Here are some more musings on pagination: http://mysql.rjweb.org/doc.php/pagination

mysql: specific item to be first and then to sort the rest chronologically to end then chronologically from beginning

Lets say I have the following table:
friends
_______
id name
1 johnny
2 tam
3 slick
4 mat
5 Rhanda
6 Tommy
7 ike
8 Spencer
9 Alan
I want to get all the friends list but I want the id 5 to be the first item in the list. I want the next item to follow chronologically until the end. Then the list start from the beginning until all results have been returned. So it should end like this...
friends
_______
id name
5 Rhanda
6 Tommy
7 ike
8 Spencer
9 Alan
1 johnny
2 tam
3 slick
4 mat
I have found and tried this but as you can imagine it's only returning the first item and then ordering the rest from 1 up. I have searched and worked on this for 2 days now and really could use some help. Any suggestions?
You can use:
order by (id >= 5) desc, id
This puts all ids 5 or greater first. Then it sorts each of the parts in ascending order.
MySQL treats boolean expressions as integers in an integer context, with 0 for false and 1 for true. So, to put the true values first, desc is needed.
You can add an expression to order clause like this:
select id, name from table
order by
case when id >= 5 then 0 else 1 end
, id

MySQL get first non null value after group by

I have a large table with data that is not unique but needs to be. This table is a result of multiple union selects so is not an actual table. I cannot make it an actual table for other reasons.
All of the UNION'd tables have an email column which will eventually be unique. The resulting records look like this:
1 ozzy#test.com Ozzy
2 test#test.com Tony
3 test#yahoo.com Steve
4 tiny#test.com
13 tony#gmail.com Tony
14 test#test.com Ozzy
15 test#yahoo.com Dave
16 tiny#test.com Tim
As you can see, some emails appear more then once with different names or non-existent names. When I add a GROUP BY email clause at the end, the results look like this:
1 ozzy#test.com Ozzy
2 test#test.com Tony
3 test#yahoo.com Steve
4 tiny#test.com
13 tony#gmail.com Tony
As you can see, email 4 does not have a name because it chose the first entry with NULL for a name. Then I tried to use GROUP_CONCAT which made the results look like this:
1 ozzy#test.com Ozzy
14 test#test.com Ozzy,Tony
15 test#yahoo.com Dave,Steve
16 tiny#test.com Tim
13 tony#gmail.com Tony
As you can see, now everyone has a name but some rows have more then one name concatenated. What I want to do is GROUP BY email and choose the first NOT NULL entry of each column for each row to theoretically look like so:
1 ozzy#test.com Ozzy
2 test#test.com Tony
3 test#yahoo.com Steve
4 tiny#test.com Tim
13 tony#gmail.com Tony
I have tried using COALESCE but it doesn't work as intended. My current query looks like so:
SELECT
id,
email,
`name`
FROM
(
SELECT
email,
`name`
FROM
multiple_tables_and_unions
) AS emails
GROUP BY email
I have removed the code from the temporary table as it contains many tables but all select the email and name column. Essentially I need a function like GROUP_COALESCE but unfortunately it does not exist. What are my options?
Try using MAX, like this:
SELECT
email,
MAX(`name`)
FROM
(
SELECT
email,
`name`
FROM
multiple_tables_and_unions
) AS emails
GROUP BY email
To select the first non null value, GROUP_CONCAT can be handy here. Below is the example:
SELECT
email,
SUBSTRING_INDEX(GROUP_CONCAT(`name`), ',',1)
FROM
(
SELECT
email,
`name`
FROM
multiple_tables_and_unions
) AS emails
GROUP BY email;

MySql - order a query result in "some mode"

I have this data on a table :
id name field
0 marco attack
1 andrea defense
2 luca medium
3 ernesto defense
4 vittorio medium
5 manuele attack
i need to order as field. BUT, the priority list order (for my example) should be defense-medium-attack.
so it must return :
andrea, ernesto, luca, vittorio, marco, manuele.
How can do it? bye
You should store the fields in a separate table and give them a sort order. Then you can join to that table.
As well as allowing you to sort efficiently, it also makes the table structure more relational - which is good.
id field sort
1 defense 1
2 medium 2
3 attack 3
id name field
0 marco 3
1 andrea 1
2 luca 2
3 ernesto 1
4 vittorio 2
5 manuele 3
select p.name,
ps.field
from players p
join playersort ps
on p.field = ps.id
order by ps.sort
SELECT
X.id,
X.name,
X.field
FROM (
SELECT id,
name,
field,
CASE field WHEN 'defense' THEN 1
WHEN 'medium' THEN 2
WHEN 'attack' THEN 3
END AS SortValue
FROM MyTable) AS X
ORDER BY X.SortValue