2010-08-06 14 views
5

que tienen una columna (varchar (255)) en una tabla de MySQL, vamos a llamarlo "palabra". ¿Cómo escribir una consulta de selección que me devuelve los valores en esta columna ordenados por caracteres en la cadena?Ordenación de caracteres de la cadena en MySQL

Por ejemplo, si uno de los discos tenían la palabra "tierra" debería ser yo volver "aehrt" y así sucesivamente, para todas las filas. ¿Hay alguna forma de hacerlo en una sola consulta?

+0

¿Cómo quieres duplicados tratados? "libro" -> "bko" o "bkoo"? Por interés, ¿por qué necesitas hacer esto? –

+0

¿Es sensible a las mayúsculas o minúsculas? –

+0

no entre mayúsculas y minúsculas –

Respuesta

5

Probablemente altamente ineficiente, pero sin necesidad de funciones definidas por el usuario:

SELECT GROUP_CONCAT(LETTER SEPARATOR '') AS ReOrderedLetters 
    FROM (SELECT 'A' as LETTER FROM <table> WHERE UPPER(`name`) like '%A%' 
     UNION ALL 
     SELECT 'B' as LETTER FROM <table> WHERE UPPER(`name`) like '%B%' 
     UNION ALL 
     SELECT 'C' as LETTER FROM <table> WHERE UPPER(`name`) like '%C%' 
     UNION ALL 
     SELECT 'D' as LETTER FROM <table> WHERE UPPER(`name`) like '%D%' 
     ... 
     UNION ALL 
     SELECT 'Y' as LETTER FROM <table> WHERE UPPER(`name`) like '%Y%' 
     UNION ALL 
     SELECT 'Z' as LETTER FROM <table> WHERE UPPER(`name`) like '%Z%' 
     ) alpha 

EDITAR

que tenía que llegar a una mejor alternativa antes de ir a la cama, de lo contrario estaría nunca he llegado a dormir; entonces aquí hay una alternativa mucho más limpia y eficiente.

he creado una tabla llamada letras con una sola columna de VARCHAR (1) llamada carta; luego se llena la mesa con las letras A a Z

CREATE TABLE IF NOT EXISTS `letters` (
    `letter` varchar(1) NOT NULL, 
    PRIMARY KEY (`letter`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

INSERT INTO `letters` (`letter`) VALUES 
('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H'),('I'),('J'),('K'),('L'),('M'), 
('N'),('O'),('P'),('Q'),('R'),('S'),('T'),('U'),('V'),('W'),('X'),('Y'),('Z'); 

a continuación:

select U.`name`, 
     GROUP_CONCAT(L.`letter` 
      ORDER BY L.`letter` ASC 
      SEPARATOR '') AS ReOrderedLetters 
    FROM `users` U 
    LEFT JOIN `letters` L ON POSITION(L.`letter` IN UPPER(U.`name`)) > 0 
GROUP BY U.`name` 
+0

uf ... prefiero definir una función :) –

+0

@Vinko - espero que mi solución modificada es más limpio –

+0

Mucho mejor, ahora parece una respuesta aceptada –

0

niños bien. Aquí hay una función de burbujas para t-sql. Puede convertir a mysql usted mismo. Resulta que a SQL Server realmente no le gustan las funciones recursivas, pero esto realmente funcionó bastante rápido.

Create Function bubblesort(@In varchar(255)) 
Returns varchar(255) 
AS 
BEGIN 
    Declare @Answer varchar(255) 
    Declare @swapped bit 
    Declare @Counter int 

    Set @Answer = @In; 
    --only need to sort strings longer than 1 
    if len(@Answer) > 1 
    BEGIN 
     While 1=1 
     BEGIN 
      Set @Counter = 1; 
      Set @swapped = 0; 
      While @Counter <= len(@Answer) - 1 
      BEGIN 
       If substring(@Answer, @Counter, 1) > substring(@Answer, @Counter + 1, 1) 
        BEGIN 
        --swap 
        Set @swapped = 1; 
        Set @Answer = Stuff(@Answer, @Counter, 2, reverse(substring(@Answer, @Counter, 2))); 
        END; 
       Set @Counter = @Counter + 1; 
      END; 
      if @swapped = 0 
      BREAK; 
     END; 
    END; 
    Return @Answer; 
END; 
go 

No se olvide de recortar los resultados

Select ltrim(myfield) from mytable; 
1

Se inserta cada letra de cada palabra en una tabla temporal y luego GROUP_CONCAT() son ellos ordenada. Probablemente esta no sea una solución muy eficiente debido al uso de un cursor y la inserción de todas las letras en una tabla temporal. Apuesto a que una rutina de clasificación será más rápida, pero necesitas algún tipo de estructura de matriz para mantener las letras si no vas a usar una tabla temporal. No estoy seguro de si los procedimientos de MySQL tienen matrices.

delimiter $$ 
drop procedure if exists sort_letters$$ 
create procedure sort_letters() 
begin 
     declare done int default 0; 
     declare word varchar(256); 
     declare cur1 cursor for select i from a; 
     declare continue handler for not found set done = 1; 
     drop temporary table if exists temp; 
     create temporary table temp (id int, letter char); 
     set @wordcount = 0; 
     open cur1; 
     repeat 
       fetch cur1 into word; 
       if not done then 
         set @counter = 0; 
         set @len = length(word); 
         while (@counter <= @len) do 
           insert into temp values 
           (@wordcount, substring(word,@counter,1)); 
           set @counter = @counter + 1; 
         end while; 
         set @wordcount = @wordcount + 1; 
       end if; 
     until done end repeat; 
     close cur1; 
     select group_concat(letter order by letter separator '') 
     from temp group by id; 
end$$ 


mysql> desc a; 
+-------+--------------+------+-----+---------+-------+ 
| Field | Type   | Null | Key | Default | Extra | 
+-------+--------------+------+-----+---------+-------+ 
| i  | varchar(256) | YES |  | NULL |  | 
+-------+--------------+------+-----+---------+-------+ 
1 row in set (0.04 sec) 

mysql> select * from a; 
+-------+ 
| i  | 
+-------+ 
| earth | 
| sand | 
| fire | 
+-------+ 
3 rows in set (0.00 sec) 

mysql> call sort_letters(); 
+---------------------------------------------------+ 
| group_concat(letter order by letter separator '') | 
+---------------------------------------------------+ 
| aehrt            | 
| adns            | 
| efir            | 
+---------------------------------------------------+ 
3 rows in set (0.00 sec) 
1

Aquí hay una alternativa interesante que representaría a cada personaje una vez. No exactamente seguro si que representa todas las letras provoca algún tipo de error de desbordamiento, pero la lógica es motivo de reflexión:

SELECT 
CONCAT(
REPEAT('a',SIGN(POSITION('a' IN word_col))), 
REPEAT('b',SIGN(POSITION('b' IN word_col))), 
REPEAT('c',SIGN(POSITION('c' IN word_col))), 
REPEAT('d',SIGN(POSITION('d' IN word_col))), 
REPEAT('e',SIGN(POSITION('e' IN word_col))), 
REPEAT('f',SIGN(POSITION('f' IN word_col))), 
... 
REPEAT('Z',SIGN(POSITION('Z' IN word_col))) 
) 
FROM 
word 

Obviamente, el "tipo" se basa en la forma en que está estructurado el CONCAT.

Cuestiones relacionadas