2009-07-28 9 views
31

Tengo una tabla MySQL donde todos los datos de una columna se ingresaron en MAYÚSCULAS, pero necesito convertirlos a Title Case, con reconocimiento de "palabras pequeñas" similar al Daring Fireball Title Case script.¿Existe una manera simple de convertir datos MySQL en Title Case?

Encontré this excellent solution para transformar cadenas a minúsculas, pero la función de título de caso parece haber quedado fuera de mi versión de MySQL. ¿Hay una manera elegante de hacer esto?

+0

¿Funciona mi respuesta para ti John? – hobodave

Respuesta

1

Woo! No soy útil con SQL en absoluto; Aquí está el método que trabajó para mí:

  1. Exportar la tabla como un archivo de texto en formato .sql.
  2. Abra el archivo en Textmate (que ya tuve a mano).
  3. Seleccione las filas con datos MAYÚSCULAS.
  4. Elija "Convertir" del menú "Texto", y seleccione "a la Portada".
  5. buscar y reemplazar cada instancia de:

    INSERT INTO `Table` (`Col1`, `Col2`, `Etc`, ...) VALUES 
    

    con los valores minúsculas según corresponda.

  6. Importa la tabla de nuevo a la base de datos.
  7. Utilice UPDATE table SET colname=LOWER(colname); para restablecer los valores en minúsculas para las columnas que deben estar en minúscula.

La razón por la que no intenté usar Textmate antes era porque no podía encontrar la manera de convertir una sola columna en Title Case sin arruinar los demás datos, pero este método parece funcionar. Gracias por su orientación y apoyo!

0

El caso definitivo para buscar una función de este tipo está en el documentation.

Desafortunadamente, tiene las funciones LOWER() y UPPER(), pero no Title Case. Su mejor opción sería declarar su propia función que se divide en espacios, ignora sus pequeñas palabras y hace un UPPER en el primer carácter de cada palabra restante.

0

La respuesta dependerá del tipo de datos en la columna, es decir, nombres de personas, nombres de lugares, títulos de libros, etc. Si está buscando una solución SQL, lo haría en varias actualizaciones , por ejemplo:

  1. secuencia inicial es: "Matar a un ruiseñor"
  2. Convertir a mayúsculas iniciales: "Matar a un Mockingbird"
  3. Convertir pequeñas palabras a minúsculas si no comienzan la cadena: "A Mata a un ruiseñor"
+1

Olvidó los pasos 4. y 5 .: 4. ??? 5. Beneficio. Bromas aparte; es un algoritmo sensato, pero ¿qué funciones integradas de MySQL pueden lograr el paso 2? – rooskie

+0

Ninguno, el OP tendrá que escribir algo de SQL. Los puntos que intentaba hacer eran 1) "Caso de título" es vago sin saber el significado de los datos; y 2) Esto se hace mejor en múltiples pasos. No voy a perder tiempo escribiendo SQL sin conocer la respuesta al punto 1.La respuesta de hobodave me parece correcta, pero no dará los resultados deseados si la columna está llena de nombres como "FLANNERY O'CONNOR". –

+1

@jamie: Tendrás que hacer excepciones especiales para los irlandeses. :-) – hobodave

1

puede hacer esto con concat(), subcadena() y longitud() pero solo puedo ver que funciona para una palabra. ¿Hay alguna razón específica por la que no puedas hacer esto en el código de tu aplicación, en lugar de mysql?

55

Editar

Eureka! Literalmente mi primera función SQL. Sin garantía ofrecida. Haga una copia de seguridad de sus datos antes de usarlos. :)

En primer lugar, define la siguiente función:

DROP FUNCTION IF EXISTS lowerword; 
SET GLOBAL log_bin_trust_function_creators=TRUE; 
DELIMITER | 
CREATE FUNCTION lowerword(str VARCHAR(128), word VARCHAR(5)) 
RETURNS VARCHAR(128) 
DETERMINISTIC 
BEGIN 
    DECLARE i INT DEFAULT 1; 
    DECLARE loc INT; 

    SET loc = LOCATE(CONCAT(word,' '), str, 2); 
    IF loc > 1 THEN 
    WHILE i <= LENGTH (str) AND loc <> 0 DO 
     SET str = INSERT(str,loc,LENGTH(word),LCASE(word)); 
     SET i = loc+LENGTH(word); 
     SET loc = LOCATE(CONCAT(word,' '), str, i); 
    END WHILE; 
    END IF; 
    RETURN str; 
END; 
| 
DELIMITER ; 

Esto reducirá todas las apariciones de la palabra en str.

después definir esta función apropiada modificación:

DROP FUNCTION IF EXISTS tcase; 
SET GLOBAL log_bin_trust_function_creators=TRUE; 
DELIMITER | 
CREATE FUNCTION tcase(str VARCHAR(128)) 
RETURNS VARCHAR(128) 
DETERMINISTIC 
BEGIN 
    DECLARE c CHAR(1); 
    DECLARE s VARCHAR(128); 
    DECLARE i INT DEFAULT 1; 
    DECLARE bool INT DEFAULT 1; 
    DECLARE punct CHAR(17) DEFAULT '()[]{},[email protected];:?/'; 
    SET s = LCASE(str); 
    WHILE i <= LENGTH(str) DO 
    BEGIN 
     SET c = SUBSTRING(s, i, 1); 
     IF LOCATE(c, punct) > 0 THEN 
     SET bool = 1; 
     ELSEIF bool=1 THEN 
     BEGIN 
      IF c >= 'a' AND c <= 'z' THEN 
      BEGIN 
       SET s = CONCAT(LEFT(s,i-1),UCASE(c),SUBSTRING(s,i+1)); 
       SET bool = 0; 
      END; 
      ELSEIF c >= '0' AND c <= '9' THEN 
      SET bool = 0; 
      END IF; 
     END; 
     END IF; 
     SET i = i+1; 
    END; 
    END WHILE; 

    SET s = lowerword(s, 'A'); 
    SET s = lowerword(s, 'An'); 
    SET s = lowerword(s, 'And'); 
    SET s = lowerword(s, 'As'); 
    SET s = lowerword(s, 'At'); 
    SET s = lowerword(s, 'But'); 
    SET s = lowerword(s, 'By'); 
    SET s = lowerword(s, 'For'); 
    SET s = lowerword(s, 'If'); 
    SET s = lowerword(s, 'In'); 
    SET s = lowerword(s, 'Of'); 
    SET s = lowerword(s, 'On'); 
    SET s = lowerword(s, 'Or'); 
    SET s = lowerword(s, 'The'); 
    SET s = lowerword(s, 'To'); 
    SET s = lowerword(s, 'Via'); 

    RETURN s; 
END; 
| 
DELIMITER ; 

Uso

verificar que esto funciona como se esperaba:

SELECT tcase(title) FROM table; 

usarlo:

UPDATE table SET title = tcase(title); 

Fuente: http://www.artfulsoftware.com/infotree/queries.php?&bw=1070#122

+0

Gracias por esto. Me salvó el día. –

+0

Trabajo impresionante: necesitaba algo que manejara acrónimos definidos por el usuario, así que he generalizado lo que tienes aquí. – CurtainDog

+0

Al usar esto obtuve este error: # 1305 - FUNCTION table_name.LENGTH no existe. ¿Me estoy perdiendo de algo? –

8

Si tiene que tirar siglas personalizados y otros patrones de capitalización personalizada en la mezcla que he generalicé respuesta de hobodave:

DELIMITER | 
CREATE FUNCTION replaceword(str VARCHAR(128), word VARCHAR(128)) 
RETURNS VARCHAR(128) 
DETERMINISTIC 
BEGIN 
    DECLARE loc INT; 
    DECLARE punct CHAR(27) DEFAULT '()[]{},[email protected];:?/''"#$%^&*<>'; 
    DECLARE lowerWord VARCHAR(128); 
    DECLARE lowerStr VARCHAR(128); 

    IF LENGTH(word) = 0 THEN 
    RETURN str; 
    END IF; 
    SET lowerWord = LOWER(word); 
    SET lowerStr = LOWER(str); 
    SET loc = LOCATE(lowerWord, lowerStr, 1); 
    WHILE loc > 0 DO 
    IF loc = 1 OR LOCATE(SUBSTRING(str, loc-1, 1), punct) > 0 THEN 
     IF loc+LENGTH(word) > LENGTH(str) OR LOCATE(SUBSTRING(str, loc+LENGTH(word), 1), punct) > 0 THEN 
     SET str = INSERT(str,loc,LENGTH(word),word); 
     END IF; 
    END IF; 
    SET loc = LOCATE(lowerWord, lowerStr, loc+LENGTH(word)); 
    END WHILE; 
    RETURN str; 
END; 
| 
DELIMITER ; 

DELIMITER | 
CREATE FUNCTION tcase(str VARCHAR(128)) 
RETURNS VARCHAR(128) 
DETERMINISTIC 
BEGIN 
    DECLARE c CHAR(1); 
    DECLARE s VARCHAR(128); 
    DECLARE i INT DEFAULT 1; 
    DECLARE bool INT DEFAULT 1; 
    DECLARE punct CHAR(27) DEFAULT '()[]{},[email protected];:?/''"#$%^&*<>'; 

    SET s = LCASE(str); 
    WHILE i <= LENGTH(str) DO 
    BEGIN 
     SET c = SUBSTRING(s, i, 1); 
     IF LOCATE(c, punct) > 0 THEN 
     SET bool = 1; 
     ELSEIF bool=1 THEN 
     BEGIN 
      IF c >= 'a' AND c <= 'z' THEN 
      BEGIN 
       SET s = CONCAT(LEFT(s,i-1),UCASE(c),SUBSTRING(s,i+1)); 
       SET bool = 0; 
      END; 
      ELSEIF c >= '0' AND c <= '9' THEN 
      SET bool = 0; 
      END IF; 
     END; 
     END IF; 
     SET i = i+1; 
    END; 
    END WHILE; 

    SET s = replaceword(s, 'a'); 
    SET s = replaceword(s, 'an'); 
    SET s = replaceword(s, 'and'); 
    SET s = replaceword(s, 'as'); 
    SET s = replaceword(s, 'at'); 
    SET s = replaceword(s, 'but'); 
    SET s = replaceword(s, 'by'); 
    SET s = replaceword(s, 'for'); 
    SET s = replaceword(s, 'if'); 
    SET s = replaceword(s, 'in'); 
    SET s = replaceword(s, 'n'); 
    SET s = replaceword(s, 'of'); 
    SET s = replaceword(s, 'on'); 
    SET s = replaceword(s, 'or'); 
    SET s = replaceword(s, 'the'); 
    SET s = replaceword(s, 'to'); 
    SET s = replaceword(s, 'via'); 

    SET s = replaceword(s, 'RSS'); 
    SET s = replaceword(s, 'URL'); 
    SET s = replaceword(s, 'PHP'); 
    SET s = replaceword(s, 'SQL'); 
    SET s = replaceword(s, 'OPML'); 
    SET s = replaceword(s, 'DHTML'); 
    SET s = replaceword(s, 'CSV'); 
    SET s = replaceword(s, 'iCal'); 
    SET s = replaceword(s, 'XML'); 
    SET s = replaceword(s, 'PDF'); 

    SET c = SUBSTRING(s, 1, 1); 
    IF c >= 'a' AND c <= 'z' THEN 
     SET s = CONCAT(UCASE(c),SUBSTRING(s,2)); 
    END IF; 

    RETURN s; 
END; 
| 
DELIMITER ; 

Esencialmente consiste en una palabra entre mayúsculas y minúsculas reemplazar la función y una función para capitalizar el primera letra de cada palabra y realizar algunas transformaciones para palabras específicas.

Espero que sea útil para alguien.

8

umm algo como esto puede funcionar

UPDATE table_name SET `col_name`= CONCAT(UPPER(SUBSTRING(`col_name`, 1, 1)) , LOWER(SUBSTRING(`col_name` FROM 2))); 
+1

El problema con esta solución es que la primera letra del valor del campo será mayúscula. Otras palabras se mantendrán en minúsculas. –

+0

¿Cómo se puede cambiar para que tenga otras palabras adecuadas? – NuWin

1

Esta funciona para mí.

UPDATE `suburbs` 
SET title2 = CONCAT_WS(' ', 
CONCAT(UPPER(LEFT(SUBSTRING_INDEX(title, ' ',1),1)), LOWER(MID(SUBSTRING_INDEX(title, ' ',1),2))), 
CONCAT(UPPER(MID(SUBSTRING_INDEX(title, ' ',2),LENGTH(SUBSTRING_INDEX(title, ' ',1)) + 2, 1)), LOWER(MID(SUBSTRING_INDEX(title, ' ',2),3 + LENGTH(SUBSTRING_INDEX(title, ' ',1))))), 
CONCAT(UPPER(MID(SUBSTRING_INDEX(title, ' ',3),LENGTH(SUBSTRING_INDEX(title, ' ',2)) + 2, 1)), LOWER(MID(SUBSTRING_INDEX(title, ' ',3),3 + LENGTH(SUBSTRING_INDEX(title, ' ',2))))), 
CONCAT(UPPER(MID(SUBSTRING_INDEX(title, ' ',4),LENGTH(SUBSTRING_INDEX(title, ' ',3)) + 2, 1)), LOWER(MID(SUBSTRING_INDEX(title, ' ',4),3 + LENGTH(SUBSTRING_INDEX(title, ' ',3))))), 
CONCAT(UPPER(MID(SUBSTRING_INDEX(title, ' ',5),LENGTH(SUBSTRING_INDEX(title, ' ',4)) + 2, 1)), LOWER(MID(SUBSTRING_INDEX(title, ' ',5),3 + LENGTH(SUBSTRING_INDEX(title, ' ',4))))), 
CONCAT(UPPER(MID(SUBSTRING_INDEX(title, ' ',6),LENGTH(SUBSTRING_INDEX(title, ' ',5)) + 2, 1)), LOWER(MID(SUBSTRING_INDEX(title, ' ',6),3 + LENGTH(SUBSTRING_INDEX(title, ' ',5))))), 
CONCAT(UPPER(MID(SUBSTRING_INDEX(title, ' ',7),LENGTH(SUBSTRING_INDEX(title, ' ',6)) + 2, 1)), LOWER(MID(SUBSTRING_INDEX(title, ' ',7),3 + LENGTH(SUBSTRING_INDEX(title, ' ',6))))), 
CONCAT(UPPER(MID(SUBSTRING_INDEX(title, ' ',8),LENGTH(SUBSTRING_INDEX(title, ' ',7)) + 2, 1)), LOWER(MID(SUBSTRING_INDEX(title, ' ',8),3 + LENGTH(SUBSTRING_INDEX(title, ' ',7))))), 
CONCAT(UPPER(MID(SUBSTRING_INDEX(title, ' ',9),LENGTH(SUBSTRING_INDEX(title, ' ',8)) + 2, 1)), LOWER(MID(SUBSTRING_INDEX(title, ' ',9),3 + LENGTH(SUBSTRING_INDEX(title, ' ',8))))), 
CONCAT(UPPER(MID(SUBSTRING_INDEX(title, ' ',10),LENGTH(SUBSTRING_INDEX(title, ' ',9)) + 2, 1)), LOWER(MID(SUBSTRING_INDEX(title, ' ',10),3 + LENGTH(SUBSTRING_INDEX(title, ' ',9))))), 
CONCAT(UPPER(MID(SUBSTRING_INDEX(title, ' ',11),LENGTH(SUBSTRING_INDEX(title, ' ',10)) + 2, 1)), LOWER(MID(SUBSTRING_INDEX(title, ' ',11),3 + LENGTH(SUBSTRING_INDEX(title, ' ',10)))))) 
WHERE 1 
3

Mi solución para caso sencillo adecuada:

CREATE FUNCTION `proper_case`(str varchar(128)) RETURNS varchar(128) 
BEGIN 
DECLARE n, pos INT DEFAULT 1; 
DECLARE sub, proper VARCHAR(128) DEFAULT ''; 

if length(trim(str)) > 0 then 
    WHILE pos > 0 DO 
     set pos = locate(' ',trim(str),n); 
     if pos = 0 then 
      set sub = lower(trim(substr(trim(str),n))); 
     else 
      set sub = lower(trim(substr(trim(str),n,pos-n))); 
     end if; 

     set proper = concat_ws(' ', proper, concat(upper(left(sub,1)),substr(sub,2))); 
     set n = pos + 1; 
    END WHILE; 
end if; 

RETURN trim(proper); 
END 

utilizarlo como:

SELECT proper_case("JOHN DOE"); 

Salida:

John Doe 
+0

Otra función similar - https://stackoverflow.com/a/33561905/4050261 –

2

he usado algo como esto

UPDATE `tablename` 
SET `fieldname` = CONCAT(UCASE(SUBSTRING(`fieldname`,1,1)),'', LCASE(SUBSTRING(`fieldname`,2,LENGTH(`fieldname`)))) 

Nota: Esto solo convertirá el primer carácter en mayúscula. y el resto del valor a minúsculas.

+0

¿Cómo puedo editar la consulta para que pueda ser el caso adecuado? – NuWin

1

Esto está trabajando para mí en mi SQL 5,0

 DELIMITER | 
     CREATE FUNCTION CamelCase(str VARCHAR(8000)) 
     RETURNS VARCHAR(8000) 
      BEGIN 
      DECLARE result VARCHAR(8000); 
      SET str = CONCAT(' ',str,' '); 
      SET result = ''; 
      WHILE LENGTH(str) > 1 DO 
       SET str = SUBSTR(str,INSTR(str,' ')+1,LENGTH(str)); 
       SET result = CONCAT(result,UPPER(LEFT(str,1)), LOWER(SUBSTR(str,2,INSTR(str,' ') - 1))) ; 
       SET str = SUBSTR(str,INSTR(str,' '),LENGTH(str)); 
      END WHILE; 
     RETURN result; 
     END 
    | 
    DELIMITER ; 
Cuestiones relacionadas