【问题标题】:mySQL Stored Function to create a slug用于创建 slug 的 mySQL 存储函数
【发布时间】:2011-07-21 13:22:26
【问题描述】:

是否有 mysql 存储函数可以从 url(或任何值)创建 slug。

所以我的查询可以是:

SELECT *, SLUG(url) FROM clients

【问题讨论】:

标签: php mysql function


【解决方案1】:

我的两分钱:

CREATE FUNCTION slugify(str VARCHAR(255))
  RETURNS VARCHAR(255)
  LANGUAGE SQL
  DETERMINISTIC
  NO SQL
  SQL SECURITY INVOKER
BEGIN
    DECLARE slug, allowed_chars VARCHAR(255);
    DECLARE current_char VARCHAR(1);
    DECLARE pos, len INT;

    -- Add here custom replaces
    SET slug = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(LOWER(TRIM(str)), 'ú', 'u'), 'ç', 'c'), 'ğ', 'g'), ' ', '-'), 'é', 'e'), 'è', 'e'), 'ë', 'e'), 'í', 'i'), 'î', 'i'), 'ò', 'o'), 'õ', 'o'), 'ù', 'u'), 'â', 'a'), 'ã', 'a'), 'ö', 'o'), 'ş', 's'), 'ì', 'i'), 'æ', 'ae'), 'à', 'a'), 'ê', 'e'), 'ñ', 'n'), 'ý', 'y'), 'ô', 'o'), 'û', 'u'), 'ï', 'i'), 'ó', 'o'), 'ü', 'u'), 'á', 'a'), 'å', 'a'), 'ä', 'a'), '_', '-');
    SET pos = 1;
    SET len = CHAR_LENGTH(slug);
    SET allowed_chars = 'abcdefghijklmnopqrstuvwxyz0123456789-';

    -- Remove not allowed characters
    WHILE pos <= len DO
        SET current_char = SUBSTRING(slug, pos, 1);
        IF LOCATE(current_char, allowed_chars) = 0 THEN
            SET slug = REPLACE(slug, current_char, '');
        END IF;
        SET pos = pos + 1;
    END WHILE;
    
    -- Squish dashes
    WHILE LOCATE('--', slug) > 0 DO
        SET slug = REPLACE(slug, '--', '-');
    END WHILE;
    
    RETURN slug;
END;

【讨论】:

    【解决方案2】:

    我已经使用这个代码很长时间了。现在在这里发帖以记住并可能帮助某人

    只需将此 sn-p 复制/粘贴到您的 MySQL 查询选项卡中并运行它。

    --假设您的用户是 root 并且主机是 localhost。如果不是,请更改 root 用户和 localhost 值以匹配您的值

    CREATE DEFINER=`root`@`localhost` FUNCTION `toSlug`(
        `s` NVARCHAR(500)
    )
    RETURNS varchar(500) CHARSET utf8
    LANGUAGE SQL
    DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY DEFINER
    COMMENT ''
    RETURN REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
    REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
    REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
    REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
    REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
    REPLACE(REPLACE(LOWER(TRIM(s)), 
    ':', ''), ')', ''), '(', ''), ',', ''), '\\', ''), '/', ''), '"', ''), '?', ''),
    "'", ''), '&', ''), '!', ''), '.', ''), ' ', '-'), '--', '-'), '--', '-'),'ù','u'),
    'ú','u'),'û','u'),'ü','u'),'ý','y'),'ë','e'),'à','a'),'á','a'),'â','a'),'ã','a'), 
    'ä','a'),'å','a'),'æ','a'),'ç','c'),'è','e'),'é','e'),'ê','e'),'ë','e'),'ì','i'),
    'í','i'),'ě','e'), 'š','s'), 'č','c'),'ř','r'), 'ž','z'), 'î','i'),'ï','i'),'ð','o'),
    'ñ','n'),'ò','o'),'ó','o'),'ô','o'),'õ','o'),'ö','o'),'ø','o'),'%', '')
    

    它会创建一个你可以调用的函数:

    UPDATE my_table set my_new_slug_column = toSlug(my_any_column_id_like_to_slug);
    

    它将获得my_any_column_id_like_to_slug的值并重写/复制到表my_table中的my_new_slug_column

    您还可以将带有文本的列转换为它的 slug,例如:

    UPDATE my_table set my_column = toSlug(my_column);
    

    这种情况会更新 my_column 本身,例如“哦,我的天哪”将是“哦,我的天哪”

    【讨论】:

      【解决方案3】:

      这是罗伯特罗斯答案的改进版本。它的速度要快得多,因为它避免了遍历所有允许的字符,并且只通过比较 ASCII 代码进行检查。

      DROP FUNCTION IF EXISTS `slugify`;
      DELIMITER ;;
      CREATE DEFINER=`root`@`localhost`
      FUNCTION `slugify`(dirty_string varchar(200))
      RETURNS varchar(200) CHARSET latin1
      DETERMINISTIC
      BEGIN
          DECLARE x, y , z Int;
          Declare temp_string, new_string VarChar(200);
          Declare is_allowed Bool;
          Declare c, check_char VarChar(1);
      
          set temp_string = LOWER(dirty_string);
      
          Set temp_string = replace(temp_string, '&', ' and ');
      
          Select temp_string Regexp('[^a-z0-9\-]+') into x;
          If x = 1 then
              set z = 1;
              While z <= Char_length(temp_string) Do
                  Set c = Substring(temp_string, z, 1);
                  Set is_allowed = False;
                  If !((ascii(c) = 45) or (ascii(c) >= 48 and ascii(c) <= 57) or (ascii(c) >= 97 and ascii(c) <= 122)) Then
                      Set temp_string = Replace(temp_string, c, '-');
                  End If;
                  set z = z + 1;
              End While;
          End If;
      
          Select temp_string Regexp("^-|-$|'") into x;
          If x = 1 Then
              Set temp_string = Replace(temp_string, "'", '');
              Set z = Char_length(temp_string);
              Set y = Char_length(temp_string);
              Dash_check: While z > 1 Do
                  If Strcmp(SubString(temp_string, -1, 1), '-') = 0 Then
                      Set temp_string = Substring(temp_string,1, y-1);
                      Set y = y - 1;
                  Else
                      Leave Dash_check;
                  End If;
                  Set z = z - 1;
              End While;
          End If;
      
          Repeat
              Select temp_string Regexp("--") into x;
              If x = 1 Then
                  Set temp_string = Replace(temp_string, "--", "-");
              End If;
          Until x <> 1 End Repeat;
      
          If LOCATE('-', temp_string) = 1 Then
              Set temp_string = SUBSTRING(temp_string, 2);
          End If;
      
          Return temp_string;
      END;;
      DELIMITER ;
      

      【讨论】:

      • 谢谢,这快了很多!您是否碰巧对下面的答案有更快的解决方案来检查蛞蝓是否是唯一的?
      • 天啊!哥们,如果你是我的女孩,我会嫁给你!这个太棒了!干得好,真的,干得好!非常感谢!
      【解决方案4】:

      我已经实现了自己的支持重音字符的 slug 函数,欢迎任何贡献。

      https://github.com/falcacibar/mysql-routines-collection/blob/master/generate_slug.func.sql

      请随时在 github 或此处发布任何建议、错误或任何问题或贡献,但最好是 github

      【讨论】:

      • 俄语字母呢?
      • 请原谅我的无知,但是我对俄语字母不太了解,但是如果你愿意,你可以贡献,你可以添加案例 =),或者你可以给我发同等的字符。
      • 当然它不能处理所有的类,它是为了解决一个特殊的需要而创建的,是为了解决 latin1 口音而开发的。我的观点是,您可以为处理更多案件做出贡献。
      • @FelipeAlcacibar 你的日常工作中的tr 函数是什么?啊,好吧,我找到了,我认为这是一个要点,但它是一个回购。
      • @ygaradon 在同一个仓库中
      【解决方案5】:

      我从 http://nastyhabit.wordpress.com/2008/09/25/mysql-slug-maker-function-aka-the-slugifier/

      并且修改它的开头不包含“-”,(我们以“$”作为第一个字符)

      这是我的结果:

      DROP FUNCTION IF EXISTS `slugify`;
      DELIMITER ;;
      CREATE DEFINER=`root`@`localhost`
      FUNCTION `slugify`(dirty_string varchar(200))
      RETURNS varchar(200) CHARSET latin1
      DETERMINISTIC
      BEGIN
          DECLARE x, y , z Int;
          Declare temp_string, allowed_chars, new_string VarChar(200);
          Declare is_allowed Bool;
          Declare c, check_char VarChar(1);
      
          set allowed_chars = "abcdefghijklmnopqrstuvwxyz0123456789-";
          set temp_string = dirty_string;
      
          Select temp_string Regexp('&') Into x;
          If x = 1 Then
              Set temp_string = replace(temp_string, '&', ' and ');
          End If;
      
          Select temp_string Regexp('[^a-z0-9]+') into x;
          If x = 1 then
              set z = 1;
              While z <= Char_length(temp_string) Do
                  Set c = Substring(temp_string, z, 1);
                  Set is_allowed = False;
                  Set y = 1;
                  Inner_Check: While y <= Char_length(allowed_chars) Do
                      If (strCmp(ascii(Substring(allowed_chars,y,1)), Ascii(c)) = 0) Then
                          Set is_allowed = True;
                          Leave Inner_Check;
                      End If;
                      Set y = y + 1;
                  End While;
                  If is_allowed = False Then
                      Set temp_string = Replace(temp_string, c, '-');
                  End If;
      
                  set z = z + 1;
              End While;
          End If;
      
          Select temp_string Regexp("^-|-$|'") into x;
          If x = 1 Then
              Set temp_string = Replace(temp_string, "'", '');
              Set z = Char_length(temp_string);
              Set y = Char_length(temp_string);
              Dash_check: While z > 1 Do
                  If Strcmp(SubString(temp_string, -1, 1), '-') = 0 Then
                      Set temp_string = Substring(temp_string,1, y-1);
                      Set y = y - 1;
                  Else
                      Leave Dash_check;
                  End If;
                  Set z = z - 1;
              End While;
          End If;
      
          Repeat
              Select temp_string Regexp("--") into x;
              If x = 1 Then
                  Set temp_string = Replace(temp_string, "--", "-");
              End If;
          Until x <> 1 End Repeat;
      
          If LOCATE('-', temp_string) = 1 Then
              Set temp_string = SUBSTRING(temp_string, 2);
          End If;
      
          Return temp_string;
      END;;
      DELIMITER ;
      

      效果很好,但是!这很慢。如果您尝试从中选择某些内容,与选择已编入索引的预填充列相比,您将在查询中增加大约 1000% 的时间。

      获得 500 个结果的时间为 0.27 秒 非 slugged(通过 mysql)为 .00003 秒

      不过,对于插入数据,这个函数会很好用!只需将 slugged 数据插入预定义的列(THATS INDEXED,因为你为什么不选择那些 slugged 的​​东西?)

      注意:要'slugified'的文本首先需要小写,因为此函数不处理大写字母(将它们转换为'-')。

      【讨论】:

      • 原版出现错误 - 这个可以直接复制/粘贴 grin - 谢谢
      • 它为我删除了第一个字符。
      • 当将两个单词(新西兰)传递给上面的函数时,上面的函数是错误的。下面Greg提供的函数没有这个问题。
      • 仍然很慢 - 一个半小时才能获得 50,000 行的 slug
      • 改变 set temp_string = dirty_string;设置 temp_string = LCASE(dirty_string);对我有帮助
      【解决方案6】:

      我在 Robert 发布的函数中添加了一些行,以确保 slug 始终是唯一的。

      这发生在函数结束之前,如下所示。确保您指定的表名不带括号 []。

          SELECT COUNT(*) INTO i FROM [table name goes here] WHERE slug LIKE CONCAT('%',temp_string,'%');
          If i > 0 Then
              Set temp_string = CONCAT(temp_string,'-',i+1);
          End If;
      
          Return temp_string;
      END;;
      DELIMITER ;
      

      【讨论】:

        【解决方案7】:

        我不确定我是否会推荐在 SQL 中执行此操作,但这里有一个人为您制作了一个名为“slugify”的函数:

        http://nastyhabit.wordpress.com/2008/09/25/mysql-slug-maker-function-aka-the-slugifier/

        【讨论】:

        • 我发现他的解决方案看起来并不吸引人......也许我可以从中获得一些想法。为什么不推荐呢?
        • 我认为在应用程序层上实现会更容易,在你的情况下是 PHP。至少,对我来说是这样。我不是 SQL 专家。对于数据格式化(这几乎就是这样),我喜欢把它留给数据的消费者。您还应该做一些速度测试,看看哪种方法更有效。我认为这将确定哪种方法适合您的情况。
        • 是的,这就是我实际上正在做的事情,试图找到一些基准数字并从那里做出决定。
        • 也许逻辑不在 PHP 或 Wordpress 中,这是在大规模 SQL 处理中。仅仅为此而逐行创建 PHP 例程会很尴尬。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-03-25
        • 1970-01-01
        • 2020-08-03
        • 2012-11-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多