2011-03-23 14 views
12

¿Hay una función almacenada de mysql para crear una babosa desde una url (o cualquier valor realmente).Función almacenada mySQL para crear una babosa

Así que mi consulta puede ser:

SELECT *, SLUG(url) FROM clients 
+0

duplicado Posible de http://stackoverflow.com/questions/3690432/ mysql-query-to-retrieve-full-url-slug – Brad

+0

que funciona en varios idiomas con la ayuda de la transliteración. http://stackoverflow.com/questions/30570865/how-to-rewrite-this-php-slugify-function-to-mysql?noredirect=1#comment49267833_30570865 – juslintek

Respuesta

2

No estoy seguro de si yo recomendaría hacer esto en SQL, pero aquí es un tipo que hizo una función para la que llamó "slugify":

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

+0

Lo encontré y su solución no se veía atractiva. .. tal vez pueda tomar algunas ideas de eso. ¿Por qué no lo sugieres? –

+2

Creo que sería más fácil implementarlo en la capa de aplicaciones, en PHP en su caso. Al menos, sería para mí. No soy un genio de SQL. Para el formato de datos (que es más o menos lo que es), me gusta dejar eso al consumidor de los datos. También debe hacer algunas pruebas de velocidad para ver qué método es más eficiente. Creo que eso determinará qué método es apropiado para su caso. – Brad

+0

Sí, eso es lo que estoy haciendo, tratando de encontrar algunos números de referencia y decidir a partir de ahí. –

7

que tomaron la Slugifier de http://nastyhabit.wordpress.com/2008/09/25/mysql-slug-maker-function-aka-the-slugifier/

Y lo modificó para que no incluya "-" en el beginni ng, (tuvimos "$" como primer carácter)

Aquí está mi resultado:

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 = "abcdefghijklmnopqrstuvwxyz-"; 
    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 ; 

funciona bien, pero! Es bastante lento Si intenta seleccionar algo fuera de esto, agregará aproximadamente el 1000% de tiempo a la consulta en comparación con la selección de una columna con slugging indexada.

slugging de 500 resultados fue .27 segundos para no slugging (a través de MySQL) fue .00003 segundos

para insertar datos, sin embargo, esta función sería un gran trabajo! Simplemente inserte los datos slugged en una columna predefinida (ESE INDEXADO, ¿por qué no seleccionaría algo que tiene slugged?)

Nota: El texto que se 'slugified' debe estar primero en minúscula, ya que esta función no manejar letras Mayúsculas (las convierte a '-').

+0

Estaba recibiendo errores con el original, este funcionaba al copiar/pegar * sonrisa * - gracias – Alvin

+0

Me quita el primer caracter. – Dennis

+0

La función anterior tiene errores cuando se pasan dos palabras (Nueva Zelanda) se convierte en ew-ealand. La función provista por Greg a continuación no tiene este problema. – Tim

2

Agregué algunas líneas a la función que Robert publicó, para asegurarme de que la barra sea siempre única.

Esto va justo antes del final de la función, como se puede ver a continuación. Asegúrese de indicar el nombre de la tabla sin los corchetes [].

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 ; 
23

Esta es una versión actualizada de la función anterior. Es mucho más rápido, ya que evita el bucle a través de todos los caracteres permitidos y simplemente comprueba al comparar los códigos 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 ; 
+0

¡Gracias, esto es mucho más rápido! ¿Tiene alguna solución más rápida a la respuesta a continuación para verificar si la babosa es única? – Brad

+0

¡OMG! Amigo, si fueras niña, ¡me casaría contigo! ¡Este es asombroso! Bien hecho, realmente, bien hecho! ¡Muchas gracias! –

+1

No funciona con símbolos no latinos. – userlond

2

He implementado mi propia función slug que admite caracteres acentuados, cualquier contribución es bienvenida.

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

No dude en enviar cualquier sugerencia, insectos o cualquier problema o contribución en github o aquí, pero es mejor github

+0

¿Qué hay del alfabeto ruso? – Dementic

+0

Disculpe mi ignorancia, pero no sé demasiado sobre el alfabeto ruso, pero puede contribuir si lo desea, puede agregar los casos =), o puede enviarme los caracteres equivalentes. –

+0

mi punto era que su código no maneja todos los casos. – Dementic

Cuestiones relacionadas