Fungsi Tersimpan mySQL untuk membuat siput

Apakah ada fungsi tersimpan mysql di luar sana untuk membuat siput dari url (atau nilai apa pun).

Jadi pertanyaan saya bisa berupa:

SELECT *, SLUG(url) FROM clients

person Robert Ross    schedule 23.03.2011    source sumber
comment
Kemungkinan duplikat stackoverflow.com/ pertanyaan/3690432/   -  person Brad    schedule 23.03.2011
comment
yang berfungsi pada berbagai bahasa dengan bantuan transliterasi. stackoverflow.com/questions/30570865/   -  person juslintek    schedule 02.06.2015


Jawaban (7)


Ini adalah versi perbaikan dari jawaban Robert Ross. Ini jauh lebih cepat karena menghindari perulangan semua karakter yang diperbolehkan dan hanya memeriksa dengan membandingkan kode 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 ;
person Gregg    schedule 07.12.2011
comment
Terima kasih, ini jauh lebih cepat! Apakah Anda memiliki solusi yang lebih cepat untuk jawaban di bawah ini untuk memeriksa apakah siput itu unik? - person Brad; 24.02.2012
comment
YA AMPUN! Kawan, jika kamu jadi aku perempuan, aku akan menikahimu! Yang ini luar biasa! Bagus sekali, sungguh, bagus sekali! Terima kasih banyak! - person Nikola Svitlica; 23.11.2015

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

Dan memodifikasinya agar tidak menyertakan "-" di awal, (Kami memiliki "$" sebagai karakter pertama)

Inilah hasil saya:

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 ;

Bekerja dengan baik, Tapi! Ini cukup lambat. Jika Anda mencoba memilih sesuatu dari ini, Anda akan menambahkan sekitar 1000% waktu ke kueri dibandingkan dengan memilih kolom yang sudah diindeks sebelumnya.

Slugged untuk 500 hasil adalah 0,27 detik Non-slugged (melalui mysql) adalah 0,00003 detik

Untuk memasukkan data, fungsi ini akan berfungsi dengan baik! Cukup masukkan data slugged ke dalam kolom yang telah ditentukan sebelumnya (ITU DIINDEKSKAN, karena mengapa Anda tidak memilih sesuatu yang slugged?)

Catatan: Teks yang akan 'di-slugifikasi' harus menggunakan huruf kecil terlebih dahulu, karena fungsi ini tidak menangani huruf Besar (mengubahnya menjadi '-').

person Robert Ross    schedule 23.03.2011
comment
Ada kesalahan dengan aslinya - yang ini langsung berfungsi hanya dengan menyalin/menempel senyum - terima kasih - person Alvin; 03.09.2011
comment
Ini menghapus karakter pertama untuk saya. - person Dennis; 26.09.2011
comment
Fungsi di atas bermasalah ketika dua kata dimasukkan ke dalamnya (Selandia Baru) menjadi ew-ealand. Fungsi yang disediakan oleh Greg di bawah ini tidak mengalami masalah ini. - person Tim; 02.05.2012
comment
Masih lambat - satu setengah jam untuk mendapatkan siput untuk 50.000 baris - person Dave Hilditch; 02.07.2015
comment
mengubah set temp_string = dirty_string; untuk mengatur temp_string = LCASE(dirty_string); sangat membantu saya - person John Corry; 11.11.2016

Saya tidak yakin apakah saya akan merekomendasikan melakukan ini dalam SQL, tapi inilah orang yang membuatkan fungsi untuk Anda yang disebut "slugify":

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

person Brad    schedule 23.03.2011
comment
Saya menemukannya dan solusinya tidak terlihat menarik... mungkin saya bisa mengambil beberapa ide darinya. Mengapa Anda tidak menyarankannya? - person Robert Ross; 23.03.2011
comment
Saya pikir akan lebih mudah untuk mengimplementasikan pada lapisan aplikasi, dalam PHP dalam kasus Anda. Setidaknya itu untukku. Saya bukan ahli SQL. Untuk pemformatan data (hampir seperti itu), saya menyerahkannya kepada konsumen data. Anda juga harus melakukan beberapa tes kecepatan, untuk melihat metode mana yang lebih efisien. Saya pikir itu akan menentukan metode mana yang sesuai untuk kasus Anda. - person Brad; 23.03.2011
comment
Ya itulah yang sebenarnya saya lakukan, mencoba mencari beberapa angka patokan dan memutuskan dari sana. - person Robert Ross; 23.03.2011
comment
Mungkin logikanya tidak ada di PHP atau Wordpress dan ini sedang dalam perawatan SQL massal. Akan terasa canggung untuk membuat rutinitas baris demi baris PHP hanya untuk ini. - person Orden; 18.12.2018

Saya menambahkan beberapa baris ke fungsi yang diposting Robert, untuk memastikan siput selalu unik.

Ini terjadi tepat sebelum akhir fungsi, seperti yang Anda lihat di bawah. Pastikan Anda mencantumkan nama tabel tanpa tanda kurung [].

    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 ;
person Eduardo J Garcia    schedule 25.10.2011

Saya telah menerapkan fungsi slug saya sendiri untuk mendukung karakter beraksen, kontribusi apa pun untuk itu diterima.

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

Jangan ragu untuk mengirimkan saran, bug, atau masalah atau kontribusi apa pun di github atau di sini tetapi github lebih baik

person Felipe Buccioni    schedule 20.05.2013
comment
Bagaimana dengan Alfabet Rusia? - person Rafael Herscovici; 12.06.2013
comment
Maaf atas ketidaktahuan saya, tetapi saya tidak tahu terlalu banyak tentang alfabet Rusia, tetapi Anda dapat berkontribusi jika mau, Anda dapat menambahkan huruf besar-kecil =), atau Anda dapat mengirimkan saya karakter yang setara. - person Felipe Buccioni; 13.06.2013
comment
Tentu saja tidak menangani semua kelas, Ini diciptakan untuk memenuhi kebutuhan tertentu, dikembangkan untuk mengatasi aksen latin1. Dan maksud saya adalah Anda dapat berkontribusi untuk menangani lebih banyak kasus. - person Felipe Buccioni; 13.06.2013
comment
@FelipeAlcacibar apa fungsi tr dalam rutinitas Anda? ahh oke saya menemukannya, saya pikir itu intinya tetapi itu adalah repo. - person ygaradon; 09.04.2014
comment
@ygaradon di repo yang sama - person Felipe Buccioni; 10.04.2014
comment
hei, fungsinya bagus, tapi menurut saya ada 2 masalah : 1. yang asli - sudah dihapus, harus tetap ada 2. ' dihapus bukannya diganti dengan - - person sHaDeoNeR; 19.11.2014

Dua sen saya:

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;
person Pioz    schedule 05.03.2021
comment
itu adalah solusi yang jelas. - person hkaraoglu; 22.06.2021

Saya telah menggunakan kode ini sejak lama. Posting di sini untuk mengingat dan mungkin membantu seseorang saat ini

cukup salin/tempel cuplikan ini di tab kueri MySQL Anda dan jalankan.

-- seandainya pengguna Anda adalah root dan host adalah localhost. Jika tidak, ubah nilai pengguna root dan localhost agar sesuai dengan milik Anda

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'),'%', '')

Ini akan membuat fungsi yang dapat Anda panggil seperti:

UPDATE my_table set my_new_slug_column = toSlug(my_any_column_id_like_to_slug);

Ini akan mendapatkan nilai my_any_column_id_like_to_slug dan menulis ulang/menyalin ke my_new_slug_column di tabel my_table

Anda juga dapat mengonversi kolom dengan teks menjadi siputnya seperti:

UPDATE my_table set my_column = toSlug(my_column);

Kasus ini akan memperbarui my_column sendiri jadi mis. 'Ya ampun' akan menjadi 'ya ampun'

person Felipe Lima    schedule 05.08.2020