I have a MySQL table where all the data in one column was entered in UPPERCASE, but I need to convert in to Title Case, with recognition of \"small words\" akin to the Darin
you could do this with concat(), substring(), and length() but I can only see it working for one word. Is there a specific reason why you can't do this in your application's code, instead of mysql?
The definitive case to look for such a function is in the documentation.
Unfortunately, you've got LOWER() and UPPER() functions, but no Title Case. Your best bet would be to declare your own function that splits on spaces, ignores your small words, and does an UPPER on the first character of each remaining word.
This is working for me In My 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 ;
The answer is going to depend on what type of data is in the column, i.e. is it people names, place names, book titles, etc. If you are looking for a SQL solution, I would do it in multiple updates, for example:
If you need to throw custom acronyms and other custom capitalisation patterns into the mix I've generalised hobodave's answer:
DELIMITER |
CREATE FUNCTION replaceword( str VARCHAR(128), word VARCHAR(128) )
RETURNS VARCHAR(128)
DETERMINISTIC
BEGIN
DECLARE loc INT;
DECLARE punct CHAR(27) DEFAULT ' ()[]{},.-_!@;:?/''"#$%^&*<>';
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 ' ()[]{},.-_!@;:?/''"#$%^&*<>';
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 ;
Essentially it consists of a case-insensitive word replace function and a function to capitalise the first letter of every word and perform some transforms for specific words.
Hope its helpful to someone.