有没有一种简单的方法可以将 MySQL 数据转换为 Title Case?

Posted

技术标签:

【中文标题】有没有一种简单的方法可以将 MySQL 数据转换为 Title Case?【英文标题】:Is there a simple way to convert MySQL data into Title Case? 【发布时间】:2010-11-14 13:33:13 【问题描述】:

我有一个 mysql 表,其中一列中的所有数据都以大写形式输入,但我需要转换为标题大小写,识别类似于 Daring Fireball Title Case script 的“小字”。

我找到了this excellent solution 用于将字符串转换为小写,但我的 MySQL 版本中似乎忽略了 Title Case 函数。有没有优雅的方法来做到这一点?

【问题讨论】:

【参考方案1】:

这在我的 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 ;

【讨论】:

【参考方案2】:

我用过这样的东西

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

注意:这只会将第一个字符转换为大写。其余的值小写。

【讨论】:

我怎样才能编辑查询,使它可以使它正确大小写?【参考方案3】:

我对简单正确案例的解决方案:

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

将其用作:

SELECT proper_case("JOHN DOE");

输出:

John Doe

【讨论】:

另一个类似的功能 - ***.com/a/33561905/4050261【参考方案4】:

编辑

尤里卡!从字面上看,我的第一个 SQL 函数。不提供保修。使用前备份您的数据。 :)

首先,定义如下函数:

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 ;

这将降低 str 中所有单词的出现次数。

然后定义这个修改后的正确函数:

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 ' ()[],.-_!@;:?/'; 
  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 ; 

用法

验证它是否按预期工作:

SELECT tcase(title) FROM table;

使用它:

UPDATE table SET title = tcase(title);

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

【讨论】:

很棒的工作 - 我需要一些可以处理用户定义的首字母缩写词的东西,所以我已经概括了你在这里得到的东西。 当使用这个我得到这个错误:#1305 - FUNCTION table_name.LENGTH 不存在。我错过了什么吗? 我最后使用了类似的东西,但使它适用于最多 4000 个字符的字符串,添加了文本列(如地址)中使用的 CR 字符(\n)作为“标点符号”单词分隔符,并在 bool=1 时将代码简化为大写所有字符,而不仅仅是 az; mysql 处理特殊字符和拉丁文等。【参考方案5】:

如果您需要将自定义首字母缩写词和其他自定义大写模式混合在一起,我已经概括了 hobodave 的答案:

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 ;

它基本上由一个不区分大小写的单词替换函数和一个将每个单词的首字母大写并对特定单词执行一些转换的函数组成。

希望它对某人有所帮助。

【讨论】:

【参考方案6】:

这个对我有用。

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

【讨论】:

【参考方案7】:

嗯,这样的事情可能会起作用

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

【讨论】:

这个解决方案的问题是字段值的第一个字母是大写的。其他单词将保持小写。 你如何改变它以使其他单词正确大小写? 只将大写字母变为大写。【参考方案8】:

哇!我根本不擅长使用 SQL。这是对我有用的方法:

    将表导出为 .sql 格式的文本文件。 在Textmate 中打开文件(我已经很方便了)。 选择包含大写数据的行。 从“Text”菜单中选择“Convert”,然后选择“to Titlecase”。

    查找并替换以下各项的每个实例:

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

    使用正确的小写值。

    将表重新导入数据库。 使用UPDATE table SET colname=LOWER(colname); 重置应为小写的列的小写值。

我之前没有尝试使用 Textmate 的原因是我无法弄清楚如何在不破坏其他数据的情况下将单列转换为标题大小写,但这种方法似乎有效。感谢您的指导和支持!

【讨论】:

嘿。因为我不熟悉函数/存储过程,我想我会完全按照你的方式来做......【参考方案9】:

您可以使用 concat()、substring() 和 length() 来做到这一点,但我只能看到它对一个词有效。为什么不能在应用程序代码而不是 mysql 中执行此操作是否有特定原因?

【讨论】:

【参考方案10】:

答案将取决于列中的数据类型,即是人名、地名、书名等。如果您正在寻找 SQL 解决方案,我会在多次更新中进行,例如:

    初始字符串为:“TO KILL A MOCKINGBIRD” 转换为初始大写:“To Kill A 知更鸟” 将小字转换为小写,如果 他们没有开始字符串:“到 杀死一只知更鸟”

【讨论】:

您忘记了步骤 4. 和 5.: 4. ??? 5. 利润。笑话不谈;这是一个明智的算法,但是 MySQL 的哪些内置函数可以完成第 2 步? 无,OP 将不得不编写一些 SQL。我试图提出的观点是 1)“标题案例”在不知道数据含义的情况下含糊不清; 2) 这最好分多个步骤完成。我不打算在不知道第 1 点答案的情况下花时间编写 SQL。hobodave 的答案对我来说是正确的,但如果列中充满了诸如“FLANNERY O'CONNOR”之类的名称,则不会给出所需的结果。跨度> @jamie:你只需要为爱尔兰人做一些特殊的例外。 :-)【参考方案11】:

寻找这种功能的最终案例是在documentation。

不幸的是,您有 LOWER() 和 UPPER() 函数,但没有标题大小写。您最好的选择是声明您自己的函数,该函数在空格上拆分,忽略您的小单词,并在每个剩余单词的第一个字符上执行 UPPER。

【讨论】:

以上是关于有没有一种简单的方法可以将 MySQL 数据转换为 Title Case?的主要内容,如果未能解决你的问题,请参考以下文章

将 T-SQL 转换为 MySQL

如何将 MySql 列名转换为小写以提高可读性?

有没有一种简单的方法可以将 C# 类转换为 PHP?

有没有一种简单的方法可以将 BigQuery 中的行转换为 JSON?

有没有一种简单的方法可以将 C++ 枚举转换为字符串?

有没有一种简单的方法可以将 Date(sql) 转换为以下格式 Month(3 character) day(int) , year(2014)