how to sort words by letters in mysql - mysql

I have a table like this...
mytbl(names)values('ron'),('sam'),('john'),('tony')
Now,I want to see the words from the names column where each word will be sorted by letters in alphabetically ascending order.I'm trying to clarify my requirements more specifically..
I want like this
'ron' will be sorted as 'nor'
'sam' will be sorted as 'ams'
'john' will be sorted as 'hjno'
'tony' will be sorted as 'noty'
and I want see exactly those sorted values as my output.How shall I get that...how should I select from the table to get such output?
Please solve my problem.thanks in advance.

You can do that in pure SQL with the help of a tally(numbers) table which you can easily create and populate like this
CREATE TABLE tally(n INT NOT NULL PRIMARY KEY);
INSERT INTO tally
SELECT a.N + b.N * 10 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
ORDER BY n
Now the query
SELECT names, GROUP_CONCAT(letter ORDER BY letter SEPARATOR '') sorted_name
FROM
(
SELECT names, MID(names, n.n, 1) letter
FROM mytbl e JOIN tally n
ON n.n <= CHAR_LENGTH(names)
) q
GROUP BY names
Output:
| NAMES | SORTED_NAME |
|-------|-------------|
| john | hjno |
| ron | nor |
| sam | ams |
| tony | noty |
Here is SQLFiddle demo

Related

How to query duplicates results MySQL

While every question I found is talking about removing duplicates I need these duplicates.
Let's say my database is
+-------+-----------+
| ID | letter |
+-------+-----------+
| 1 | A |
| 2 | B |
| 4 | Z |
+-------+-----------+
I need to query a person name so let say the name is "ABA" when I query like this
select * from letters where letter = 'A' or letter = 'B' or letter = 'A'
My result will be
+-------+-----------+
| ID | letter |
+-------+-----------+
| 1 | A |
| 2 | B |
+-------+-----------+
I want the output will include the 3rd letter as a separate row.
+-------+-----------+
| ID | letter |
+-------+-----------+
| 1 | A |
| 2 | B |
| 3 | A |
+-------+-----------+
Maybe I don't know the right term but I didn't find even one answer that give me half a solution.
there is one entry but can I can the entry again? if I query for "nina" get the full name and not just "nia"
Original answer (and recommended approach)
Use a recursive query to convert the name into rows with one letter each. Then join with your letters table.
with recursive word_letters (word, pos, letter) as
(
select #name, 1, substr(#name, 1, 1)
union all
select word, pos + 1, substr(word, pos + 1, 1)
from word_letters
where pos < length(word)
)
select letters.*
from word_letters
join letters on letters.letter = word_letters.letter
order by word_letters.pos;
Demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=6547c21d2dd9223270615047d46d9783
UPDATE: Workaround for old MySQL versions
Build a table of positions (numbers) large enough to cover the longest word. Then join the word in order to get the position for each letter in it. Then join your other table.
select letters.*
from
(
select hundreds.digit * 100 + tens.digit * 10 + units.digit + 1 as pos
from (select 0 as digit union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) units
cross join (select 0 as digit union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) tens
cross join (select 0 as digit union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) hundreds
) positions
join (select #name as word) w on length(w.word) >= positions.pos
join letters on letters.letter = substr(w.word, positions.pos, 1)
order by positions.pos;
Demo: https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=db3762d5705ce5eb77e628c4d4058485
You can do it by using any of the below queries. For your reference visit the link below to test the output.
http://sqlfiddle.com/#!9/c5e9f3/1
The table created and the populated data is as below
create table tbl(ID int,letter varchar(2));
insert into tbl(ID,letter) values(1,'A');
insert into tbl(ID,letter) values(2,'B');
insert into tbl(ID,letter) values(3,'A');
insert into tbl(ID,letter) values(4,'Z');
insert into tbl(ID,letter) values(5,'C');
and now the query
select * from tbl where letter in ('A','B');
or
select * from tbl where letter ='A' or letter='B';

MySQL - Ordering Values inside a field [duplicate]

I have table:
+-----+------------+--------------+
| id | title | numbers |
| 2 | Title 1 | 2,8,5 |
| 3 | Title 2 | 50,7,9,4 |
+-----+------------+--------------+
Is it possible to sort within the column? In this case in column numbers.
I need to output ordered numbers column as follows:
+-----+------------+--------------+
| id | title | numbers |
| 2 | Title 1 | 2,5,8 |
| 3 | Title 2 | 4,7,9,50 |
+-----+------------+--------------+
Something like:
SELECT id, title, SORT_FUNC(numbers) from table
I was looking for some function in MySQL documentation, but I found nothing.
It is possible, but not really a good idea.
As an example, you can split a comma separated list up by generating a range of numbers and using that with SUBSTRING_INDEX to get each element. However the range of numbers needs to be as big as the max number of delimited values.
You could then use GROUP_CONCAT to join the list back together in the right order. Note that the order will be different depending on whether you have cast the split up values as numbers / integers or left them as strings.
SELECT id, title, GROUP_CONCAT(aNumber ORDER BY aNumber)
FROM
(
SELECT id, title, CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(numbers, ',', tens.acnt * 10 + units.acnt + 1), ',', -1) AS UNSIGNED) AS aNumber
FROM some_table
CROSS JOIN
(SELECT 0 AS acnt UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
CROSS JOIN
(SELECT 0 AS acnt UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
WHERE LENGTH(numbers) - LENGTH(REPLACE(numbers, ',', '')) >= tens.acnt * 10 + units.acnt
) sub0
GROUP BY id, title;
Demonstrated here on SQL fiddle (if SQL fiddle decides to work):-
http://www.sqlfiddle.com/#!9/c9703ee/4
First select is casting the values as integers to sort them numerically, 2nd one isn't casting them but just leaving them as strings, hence the sort order is different.

MySQL - sort comma separated string in column

I have table:
+-----+------------+--------------+
| id | title | numbers |
| 2 | Title 1 | 2,8,5 |
| 3 | Title 2 | 50,7,9,4 |
+-----+------------+--------------+
Is it possible to sort within the column? In this case in column numbers.
I need to output ordered numbers column as follows:
+-----+------------+--------------+
| id | title | numbers |
| 2 | Title 1 | 2,5,8 |
| 3 | Title 2 | 4,7,9,50 |
+-----+------------+--------------+
Something like:
SELECT id, title, SORT_FUNC(numbers) from table
I was looking for some function in MySQL documentation, but I found nothing.
It is possible, but not really a good idea.
As an example, you can split a comma separated list up by generating a range of numbers and using that with SUBSTRING_INDEX to get each element. However the range of numbers needs to be as big as the max number of delimited values.
You could then use GROUP_CONCAT to join the list back together in the right order. Note that the order will be different depending on whether you have cast the split up values as numbers / integers or left them as strings.
SELECT id, title, GROUP_CONCAT(aNumber ORDER BY aNumber)
FROM
(
SELECT id, title, CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(numbers, ',', tens.acnt * 10 + units.acnt + 1), ',', -1) AS UNSIGNED) AS aNumber
FROM some_table
CROSS JOIN
(SELECT 0 AS acnt UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
CROSS JOIN
(SELECT 0 AS acnt UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
WHERE LENGTH(numbers) - LENGTH(REPLACE(numbers, ',', '')) >= tens.acnt * 10 + units.acnt
) sub0
GROUP BY id, title;
Demonstrated here on SQL fiddle (if SQL fiddle decides to work):-
http://www.sqlfiddle.com/#!9/c9703ee/4
First select is casting the values as integers to sort them numerically, 2nd one isn't casting them but just leaving them as strings, hence the sort order is different.

How do I return a single row for each value in a comma delimited field?

I have a select statement which fetches a value field on an ID
177,175,173,178,179
What is returned is anywhere from null, a single entry, to multiple comma delimited values in this field.
How can I use SQL to return 1 row for each value based on this comma delimited field?
As it has already been mentioned in comments consider to normalize your data to be able to normally maintain and query your data.
In the meantime you achieve your goal in pure SQL with the help of tally(number) table which you can create like this
CREATE TABLE tally (n INT NOT NULL PRIMARY KEY);
INSERT INTO tally
SELECT a.N + b.N * 10 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
ORDER BY n;
Now your might look like
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(value, ',', n), ',', -1) value
FROM table1 CROSS JOIN tally
WHERE id = 1
AND n <= 1 + (LENGTH(value) - LENGTH(REPLACE(value, ',', '')))
Output:
| VALUE |
|-------|
| 177 |
| 175 |
| 173 |
| 178 |
| 179 |
Here is SQLFiddle demo

Get value even if it doesn't exist in table from SQL SELECT statement

I have a MySQL table that looks something like this:
|---ID---|---COUNTER---|
| 1 | 2 |
| 2 | 6 |
| 3 | 1 |
| 5 | 9 |
| 6 | 10 |
I'm looking for a SELECT statement that returns ID's and their COUNTER. The table only have ID's such as: 1,2,3,5,6. Is there a statement where you say: I want ID's 1 to 10 even if they doesn't exist in the table, and if the ID doesn't exist, return the ID anyway with the COUNTER value 0. For example:
|---ID---|---COUNTER---|
| 1 | 2 |
| 2 | 6 |
| 3 | 1 |
| 4 | 0 |
| 5 | 9 |
| 6 | 10 |
| 7 | 0 |
| 8 | 0 |
| 9 | 0 |
| 10 | 0 |
Do I have to create a SELECT statement that contains NOT EXIST parameters?
Thanks in advance, Steve-O
Without creating a temp table:
select t.num as id, coalesce(yt.counter, 0)
from your_table yt
right join (
select 1 as num union select 2 union select 3 union select 4 union select 5 union
select 6 union select 7 union select 8 union select 9 union select 10
) t on yt.id = t.num
order by t.num
and bit more general:
select t.num as id, coalesce(yt.counter, 0)
from your_table yt
right join (
select t1.num + t2.num * 10 + t3.num * 100 as num
from (
select 1 as num union select 2 union select 3 union select 4 union select 5 union
select 6 union select 7 union select 8 union select 9 union select 0
) t1
cross join (
select 1 as num union select 2 union select 3 union select 4 union select 5 union
select 6 union select 7 union select 8 union select 9 union select 0
) t2
cross join (
select 1 as num union select 2 union select 3 union select 4 union select 5 union
select 6 union select 7 union select 8 union select 9 union select 0
) t3
) t on yt.id = t.num
where t.num between (select min(id) from your_table) and (select max(id) from your_table)
You can define limit by yourself here I've used min and max of id value from your_table.
It's not very robust, but if you created a temporary table with the ID's you wanted in it, you could then left join to your table containing ID and Counter which would include all the values:
Declare #tempidtable as table ( imaginaryid int )
insert into #tempidtable ( imaginaryid ) values ( 1 )
insert into #tempidtable ( imaginaryid ) values ( 2 )
insert into #tempidtable ( imaginaryid ) values ( 3 )
select
#temptable.imaginaryid,
ISNULL(yourothertable.counter, 0)
from #tempidtable
left join yourothertable
on #tempidtable.imaginaryid = yourothertable.id
As Tomek says you could loop over the inserts to make it easier to maintain, or possible store the ids you want as a base in another table, using this as the basis for the join rather than a temp table.
Create a table with all possible ID's:
create table Numbers (nr int primary key);
declare i int default 1;
while i < 100000 do
insert into Numbers (nr) values (i);
set i = i + 1;
end while;
Then you can use left join to return all numbers:
select n.NR
, c.Counter
from Numbers n
left join
Counters c
on c.ID = n.NR
You can use left join to solve your issue. Read more about left join here
I think you will have to create (generate in loop) temporary table with the complete sequence of numbers from 1 to N (where N is the MAX(Id) of counted table). Then do left join to that table and apply GROUP BY clause.
You need the range of integers to do an outer join with your table based on ID. Generating a range of integers is dependent on the SQL vendor if you do not want to use a temporary table. See SQL SELECT to get the first N positive integers for hints on how to do this based on your SQL vendor.