2009-07-28 16 views
31

Ho una tabella MySQL in cui tutti i dati in una colonna sono stati inseriti in MAIUSCOLA, ma ho bisogno di convertirli in Title Case, con riconoscimento di "parole piccole" simili a Daring Fireball Title Case script.C'è un modo semplice per convertire i dati MySQL in Title Case?

Ho trovato this excellent solution per la trasformazione delle stringhe in minuscolo, ma la funzione Title Case sembra essere stata esclusa dalla mia versione di MySQL. C'è un modo elegante per farlo?

+0

Si può usare l'risposta per voi John? – hobodave

risposta

1

Woo! Non sono affatto a portata di mano con SQL; Ecco il metodo che ha funzionato per me:

  1. Esportare la tabella come file di testo in formato .sql.
  2. Aprire il file in Textmate (che avevo già a portata di mano).
  3. Selezionare le righe con i dati MAIUSCOLE.
  4. Scegliere "Converti" dal menu "Testo" e selezionare "su Titlecase".
  5. trovare e sostituire ogni istanza:

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

    con i valori corretti minuscole.

  6. Importare nuovamente la tabella nel database.
  7. Utilizzare UPDATE table SET colname=LOWER(colname); per reimpostare i valori in minuscolo per le colonne che devono essere in minuscolo.

Il motivo per cui non ho provato a utilizzare Textmate prima era che non riuscivo a capire come convertire una singola colonna in Title Case senza rovinare gli altri dati, ma questo metodo sembra funzionare. Grazie per la tua guida e supporto!

0

Il caso definitivo per cercare tale funzione è nello documentation.

Sfortunatamente, hai le funzioni LOWER() e UPPER(), ma non Title Case. La soluzione migliore sarebbe dichiarare la propria funzione che si divide su spazi, ignora le parole piccole e fa un UPPER sul primo carattere di ogni parola rimanente.

0

La risposta dipende dal tipo di dati presenti nella colonna, ovvero nomi di persone, nomi di luoghi, titoli di libri, ecc. Se si sta cercando una soluzione SQL, lo farei in più aggiornamenti , per esempio:

  1. stringa iniziale è: "buio oltre la siepe"
  2. Converti in iniziale caps: "To Kill a Mockingbird"
  3. Convertire piccole parole in minuscolo se essi non iniziano la stringa: "To Kill a Mockingbird"
+1

Hai dimenticato i passaggi 4. e 5 .: 4. ??? 5. Profitto. Battute a parte; è un algoritmo ragionevole, ma quali funzioni MySQL integrate possono eseguire il passaggio 2? – rooskie

+0

Nessuno, l'OP dovrà scrivere qualche SQL. I punti che stavo cercando di fare erano 1) "Title case" è vago senza conoscere il significato dei dati; e 2) Questo è meglio fatto in più passaggi. Non ho intenzione di sprecare tempo a scrivere SQL senza conoscere la risposta al punto 1.La risposta di hobodave mi sembra giusta ma non darà i risultati desiderati se la colonna è piena di nomi come "FLANNERY O'CONNOR". –

+1

@jamie: Dovrai solo fare eccezioni speciali per gli irlandesi. :-) – hobodave

1

si potrebbe fare questo con concat(), sottostringa() e lunghezza() ma posso vederlo solo lavorando per una parola. C'è una ragione specifica per cui non puoi farlo nel codice dell'applicazione, invece di mysql?

55

Modifica

Eureka! Letteralmente la mia prima funzione SQL. Nessuna garanzia offerta. Eseguire il backup dei dati prima dell'uso. :)

Innanzitutto, definire la seguente funzione:

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 ; 

Questo abbasserà tutte le occorrenze di parola in str.

quindi definire questa modifica il corretto funzionamento:

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

Verificare funziona come previsto:

SELECT tcase(title) FROM table; 

usarlo:

UPDATE table SET title = tcase(title); 

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

+0

Grazie per questo. Ho salvato la mia giornata. –

+0

Lavoro fantastico - Avevo bisogno di qualcosa che gestisse gli acronimi definiti dall'utente, quindi ho generalizzato quello che hai qui. – CurtainDog

+0

Quando si utilizza questo ho ottenuto questo errore: # 1305 - FUNZIONE table_name.LENGTH non esiste. Mi sto perdendo qualcosa? –

8

Se avete bisogno di gettare acronimi personalizzati e altri modelli di capitalizzazione personalizzato nel mix che ho generalizzato risposta di 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 ; 

Essa consiste in una parola case-insensitive funzione di sostituzione e una funzione di capitalizzare il prima lettera di ogni parola ed eseguire alcune trasformazioni per parole specifiche.

Spero che sia utile a qualcuno.

8

umm qualcosa come questo può funzionare

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

Il problema con questa soluzione è solo la prima lettera del valore del campo sarà maiuscola. Altre parole rimarranno in minuscolo. –

+0

Come puoi cambiarlo in modo che le altre parole siano corrette? – NuWin

1

Questo funziona per me.

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

La mia soluzione per semplice caso una corretta:

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 

usarlo come:

SELECT proper_case("JOHN DOE"); 

uscita:

John Doe 
+0

Un'altra funzione simile - https://stackoverflow.com/a/33561905/4050261 –

2

ho usato qualcosa di simile

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

Nota: Questo sarà convertire solo il primo carattere in maiuscolo. e resto del valore in lettere minuscole.

+0

Come posso modificare la query in modo che possa renderla corretta? – NuWin

1

Questo sta lavorando per me nella mia 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 ;