วิธีการทำนิพจน์ปกติแทนใน MySQL?


515

ฉันมีตารางที่มีแถว ~ 500k คอลัมน์ varchar (255) UTF8 filenameมีชื่อไฟล์

ฉันพยายามดึงตัวละครแปลก ๆ ออกจากชื่อไฟล์ - คิดว่าฉันจะใช้คลาสตัวละคร: [^a-zA-Z0-9()_ .\-]

ตอนนี้มีฟังก์ชั่นใน MySQL ที่ให้คุณแทนที่การแสดงออกปกติหรือไม่? ฉันกำลังมองหาฟังก์ชั่นที่คล้ายกับฟังก์ชัน REPLACE () - ตัวอย่างง่าย ๆ ดังต่อไปนี้:

SELECT REPLACE('stackowerflow', 'ower', 'over');

Output: "stackoverflow"

/* does something like this exist? */
SELECT X_REG_REPLACE('Stackoverflow','/[A-Zf]/','-'); 

Output: "-tackover-low"

ฉันรู้เกี่ยวกับREGEXP / RLIKEแต่สิ่งเหล่านั้นเพียงตรวจสอบว่ามีการแข่งขันไม่ใช่สิ่งที่ตรงกับ

(ฉันสามารถทำ " SELECT pkey_id,filename FROM foo WHERE filename RLIKE '[^a-zA-Z0-9()_ .\-]'" จากสคริปต์ PHP ทำpreg_replaceแล้ว " UPDATE foo ... WHERE pkey_id=..." แต่ดูเหมือนแฮ็คสุดท้ายช้า & น่าเกลียดแฮ็ค)


8
มันเป็นคำขอคุณสมบัติตั้งแต่ปี 2007: bugs.mysql.com/bug.php?id=27389 หากคุณต้องการคุณสมบัตินี้จริงๆให้เข้าสู่ระบบและคลิกที่ปุ่ม "ส่งถึงฉัน" หวังว่ามันจะได้รับคะแนนเสียงเพียงพอ
TMS

4
@ โทมัส: ฉันได้ทำอย่างนั้น ... ในปี 2009 เมื่อฉันมองไปรอบ ๆ มัน เนื่องจากไม่มีความคืบหน้าเป็นศูนย์ - ดูเหมือนว่ามันไม่ใช่คุณสมบัติที่สำคัญ (btw Postgres มีไว้ที่: stackoverflow.com/questions/11722995/ … )
Piskvor ออกจากอาคาร

1
คำถามรุ่นที่เกี่ยวข้องง่ายกว่านี้: stackoverflow.com/questions/6942973/…
Kzqai

2
ฉันได้สร้างregexp_split(ฟังก์ชั่น + ขั้นตอน) & regexp_replaceซึ่งนำไปใช้กับREGEXPโอเปอเรเตอร์ สำหรับการค้นหาง่าย ๆ มันจะทำการหลอกลวง คุณอาจพบว่าที่นี่ - ดังนั้นนี่คือวิธีที่มีรหัสที่เก็บไว้ใน MySQL ไม่มี UDF หากคุณพบข้อบกพร่องบางอย่างซึ่งไม่ได้ครอบคลุมอยู่ในข้อ จำกัด ที่เป็นที่รู้จักโปรดอย่าลังเลที่จะเปิดปัญหา
Alma Do

1
พบไลบรารีนี้จากเธรด SO อื่น: github.com/mysqludf/lib_mysqludf_pregทำงานได้อย่างสมบูรณ์
Kyle

คำตอบ:


77

ด้วยMySQL 8.0+คุณสามารถใช้REGEXP_REPLACEฟังก์ชันได้

12.5.2 นิพจน์ปกติ :

REGEXP_REPLACE(expr, pat, repl[, pos[, occurrence[, match_type]]])

แทนที่เกิดขึ้นในสตริงexprที่ตรงกับการแสดงออกปกติที่ระบุโดยรูปแบบตบเบา ๆกับการเปลี่ยนสตริงreplและกลับสตริงที่เกิด ถ้าexpr , patหรือreplเป็นค่าตอบแทนเป็นNULLNULL

และการสนับสนุนการแสดงออกปกติ :

ก่อนหน้านี้MySQLใช้ไลบรารีนิพจน์ทั่วไปของ Henry Spencer เพื่อสนับสนุนตัวดำเนินการนิพจน์ทั่วไป ( REGEXP, RLIKE)

การสนับสนุนการแสดงออกปกติได้ถูกนำมาใช้ใหม่โดยใช้ International Components for Unicode (ICU) ซึ่งให้การสนับสนุน Unicode แบบเต็มและมีความปลอดภัยหลายไบต์ REGEXP_LIKE()ฟังก์ชั่นดำเนินการจับคู่แสดงออกปกติในลักษณะของREGEXPและRLIKEผู้ประกอบการซึ่งขณะนี้มีคำพ้องความหมายสำหรับฟังก์ชั่นที่ นอกจากนี้ REGEXP_INSTR(), REGEXP_REPLACE()และ REGEXP_SUBSTR() ฟังก์ชั่นที่มีอยู่เพื่อหาตำแหน่งการแข่งขันและดำเนิน substring ทดแทนและการสกัดตามลำดับ

SELECT REGEXP_REPLACE('Stackoverflow','[A-Zf]','-',1,0,'c'); 
-- Output:
-tackover-low

การสาธิต DBFiddle


146

MySQL 8.0+ :

คุณสามารถใช้REGEXP_REPLACEฟังก์ชั่นพื้นเมือง

รุ่นเก่ากว่า:

คุณสามารถใช้ที่ผู้ใช้กำหนดฟังก์ชั่น ( UDF ) เช่นMySQL-UDF-regexp


3
REGEXP_REPLACE เป็นฟังก์ชั่นที่ผู้ใช้กำหนด? ดูมีแนวโน้มจะดูเป็นมัน ขอบคุณ!
Piskvor ออกจากอาคาร

15
น่าเสียดายที่ mysql-udf-regexp ดูเหมือนจะไม่รองรับอักขระหลายไบต์ regexp_replace ('äöõü', 'ä', '') ส่งคืนสตริงตัวเลขที่ยาวแทนข้อความจริง
lkraav

3
MySQL ไม่รองรับอักขระแบบหลายไบต์พร้อมคุณสมบัติ RegEx
แบรด

4
ผู้ใช้ Windows: ไลบรารี UDF ที่ลิงก์ที่นี่ดูเหมือนจะไม่มีหน้าต่างรองรับที่ดี วิธีการติดตั้ง windows ที่ระบุไว้ใช้งานไม่ได้สำหรับฉัน
Jonathan

2
@lkraav คุณควรลองใช้ไลบรารี lib_mysqludf_preg ด้านล่างเนื่องจากใช้งานได้ดี นี่เป็นเวอร์ชัน verbose เมื่อมันส่งคืน blob ตามค่าเริ่มต้นและฉันไม่รู้ว่าคุณมีชุดอักขระหลายไบต์เป็นค่าเริ่มต้นของคุณ: select cast (TR as char) COLLATE utf8_unicode_ci จาก (select preg_replace ('/ ä /', '', 'öõüä') R) T
gillyspy

124

ใช้ MariaDB แทน มันมีฟังก์ชั่น

REGEXP_REPLACE(col, regexp, replace)

ดูเอกสาร MariaDBและการปรับปรุงการแสดงออกปกติ PCRE

โปรดทราบว่าคุณสามารถใช้การจัดกลุ่ม regexp เช่นกัน (ฉันพบว่ามีประโยชน์มาก):

SELECT REGEXP_REPLACE("stackoverflow", "(stack)(over)(flow)", '\\2 - \\1 - \\3')

ผลตอบแทน

over - stack - flow

12
นี่คือจาก mariadb 10
Nick

6
สำหรับครั้งต่อไปที่ฉันต้องการมันนี่คือไวยากรณ์สำหรับการเปลี่ยนทั้งคอลัมน์: UPDATE table SET Name = REGEXP_REPLACE(Name, "-2$", "\\1")สิ่งนี้จะลบ -2 จาก abcxyz-2 จากทั้งคอลัมน์ในครั้งเดียว
Josiah

27
การเปลี่ยนแพลตฟอร์มทั้งหมดนั้นแทบจะเป็นทางออกที่ไม่สมจริง
David Baucum

3
@DavidBaucum MariaDB เป็นการแทนที่สำหรับ MySQL ดังนั้นจึงไม่มี "การเปลี่ยนแปลงของแพลตฟอร์ม" แต่ชอบเลือกสายการบินอื่นสำหรับการเดินทางเดียวกัน
Benvorth


113

วิธีบังคับเดรัจฉานของฉันเพื่อให้งานนี้เป็นเพียง:

  1. ทิ้งโต๊ะ - mysqldump -u user -p database table > dump.sql
  2. ค้นหาและแทนที่แพทเทิร์นคู่ - find /path/to/dump.sql -type f -exec sed -i 's/old_string/new_string/g' {} \;, มีนิพจน์เชิงพีชคณิตเชิงเส้นอื่น ๆ ที่คุณสามารถใช้กับไฟล์ได้เช่นกัน
  3. นำเข้าตาราง - mysqlimport -u user -p database table < dump.sql

ถ้าคุณต้องการตรวจสอบให้แน่ใจว่าสตริงไม่ได้อยู่ที่อื่นในชุดข้อมูลของคุณให้เรียกใช้การแสดงออกปกติบางอย่างเพื่อให้แน่ใจว่าพวกเขาทั้งหมดเกิดขึ้นในสภาพแวดล้อมที่คล้ายกัน นอกจากนี้ยังไม่ยากที่จะสร้างการสำรองข้อมูลก่อนที่คุณจะทำการแทนที่ในกรณีที่คุณทำลายบางสิ่งที่สูญเสียความลึกของข้อมูลโดยไม่ตั้งใจ


33
โอเคนั่นน่าจะใช้ได้เช่นกัน ฉันไม่ได้พิจารณาการแทนที่แบบออฟไลน์ มีความคิดนอกกรอบที่ดีที่นั่น!
Piskvor ออกจากอาคาร

10
ดูเหมือนว่าแปลกสำหรับฉันที่คุณจะใช้งานเช่นนั้นฉันจะย่อคำสั่งให้กด -i 's / old_string / new_string / g'
/path/to/dump.sql

36
มีความเสี่ยงและไม่น่าปฏิบัติกับชุดข้อมูลขนาดใหญ่หรือมี Referential Integrity: สำหรับการลบข้อมูลแล้วใส่อีกครั้งคุณจะต้องปิด Referential Integrity ทิ้งไว้ในฐานข้อมูลของคุณ
Raul Luna

5
ในอดีตที่ผ่านมาฉันเคยใช้วิธีนี้มาก่อนกับราอูลมันมีความเสี่ยงมาก คุณต้องมีความมั่นใจอย่างแน่นอนเช่นกันว่าสตริงของคุณไม่ได้อยู่ในชุดข้อมูลของคุณ
eggmatters

1
หลายปีที่ผ่านมาคำตอบ @speshak แต่เหตุผลที่ฉันเลือกที่จะเข้าถึงไฟล์แบบนี้ก็เพราะฉันเดิมกังวลมากด้วยเหตุผลเดียวกันกับที่กล่าวข้างต้น ตอนที่มันดูเหมือนจะแยก "พบไฟล์" ส่วนหนึ่งจาก "แทนที่" ส่วนหนึ่งจะทำให้รหัสให้อ่านง่ายขึ้นก่อนที่ผมจะส่ง
ไรอันวอร์ด

42

เราแก้ปัญหานี้โดยไม่ต้องใช้ regex แบบสอบถามนี้แทนที่สตริงการจับคู่ที่แน่นอนเท่านั้น

update employee set
employee_firstname = 
trim(REPLACE(concat(" ",employee_firstname," "),' jay ',' abc '))

ตัวอย่าง:

emp_id employee_firstname

1 เจย์

2 เจย์เจ

3 เจย์

หลังจากดำเนินการผลลัพธ์คิวรี:

emp_id employee_firstname

1 ตัว

2 abc ajay

3 ตัว


@yellowmelon คำพูดคู่สองคู่สำหรับอะไร
codecowboy

5
เขาขยายชื่อผู้ใช้ที่มีช่องว่างก่อนและหลัง สิ่งนี้ทำให้เขาสามารถค้นหา - replace สำหรับ (ช่องว่าง) ชื่อผู้ใช้ (ช่องว่าง) ซึ่งหลีกเลี่ยงการจับชื่อ "jay" ของ jobeen หากเป็นส่วนหนึ่งของสตริงที่มีขนาดใหญ่กว่า "ajay" จากนั้นเขาจะตัดช่องว่างออกเมื่อเสร็จสิ้น
Slam

42

ฉันเพิ่งเขียนฟังก์ชัน MySQL เพื่อแทนที่สตริงโดยใช้นิพจน์ทั่วไป คุณสามารถค้นหาโพสต์ของฉันได้ที่ตำแหน่งต่อไปนี้:

http://techras.wordpress.com/2011/06/02/regex-replace-for-mysql/

นี่คือรหัสฟังก์ชั่น:

DELIMITER $$

CREATE FUNCTION  `regex_replace`(pattern VARCHAR(1000),replacement VARCHAR(1000),original VARCHAR(1000))
RETURNS VARCHAR(1000)
DETERMINISTIC
BEGIN 
 DECLARE temp VARCHAR(1000); 
 DECLARE ch VARCHAR(1); 
 DECLARE i INT;
 SET i = 1;
 SET temp = '';
 IF original REGEXP pattern THEN 
  loop_label: LOOP 
   IF i>CHAR_LENGTH(original) THEN
    LEAVE loop_label;  
   END IF;
   SET ch = SUBSTRING(original,i,1);
   IF NOT ch REGEXP pattern THEN
    SET temp = CONCAT(temp,ch);
   ELSE
    SET temp = CONCAT(temp,replacement);
   END IF;
   SET i=i+1;
  END LOOP;
 ELSE
  SET temp = original;
 END IF;
 RETURN temp;
END$$

DELIMITER ;

ตัวอย่างการดำเนินการ:

mysql> select regex_replace('[^a-zA-Z0-9\-]','','2my test3_text-to. check \\ my- sql (regular) ,expressions ._,');

25
ฉันจะเสริมจุดด้านบน: ฟังก์ชั่นนี้จะแทนที่ตัวละครที่ตรงกับการแสดงออกของตัวละครเดียว มันบอกว่าข้างต้นมันถูกใช้ "เพื่อ repalce สตริงโดยใช้การแสดงออกปกติ" และที่อาจทำให้เข้าใจผิดเล็กน้อย มันทำงานได้ แต่ไม่ใช่งานที่ถูกขอ (ไม่ใช่เรื่องร้องเรียน - มันเป็นเพียงการช่วยคนชั้นนำให้ลงไปในทางที่ผิด)
เจสัน

2
มันจะมีประโยชน์มากกว่าถ้าคุณใส่รหัสลงไปในคำตอบของคุณแทนที่จะโพสต์ลิงค์เปล่า ๆ
phobie

2
ดี - แต่น่าเสียดายที่ไม่ได้เกี่ยวข้องกับการอ้างอิงเช่นselect regex_replace('.*(abc).*','\1','noabcde')(ส่งคืน 'noabcde' ไม่ใช่ 'abc')
Izzy

@ phobie มีคนอื่นทำเช่นนั้นในคำตอบนี้ - เช่นเดียวกับข้อมูลอ้างอิงในกรณีที่ลิงก์เสียชีวิต)
Izzy

ฉันได้แก้ไขวิธีนี้เพื่อพยายามระบุข้อ จำกัด บางอย่างที่กล่าวถึงข้างต้นและอื่น ๆ โปรดดูคำตอบนี้
Steve Chambers

14

ฉันยินดีที่จะรายงานว่าเนื่องจากคำถามนี้ถูกถามตอนนี้มีคำตอบที่น่าพอใจ! ดูแพ็คเกจที่ยอดเยี่ยมนี้:

https://github.com/mysqludf/lib_mysqludf_preg

ตัวอย่าง SQL:

SELECT PREG_REPLACE('/(.*?)(fox)/' , 'dog' , 'the quick brown fox' ) AS demo;

ฉันพบแพ็คเกจจากโพสต์บล็อกนี้ตามลิงก์ในคำถามนี้


13

อัปเดต 2:ชุดฟังก์ชัน regex ที่มีประโยชน์ซึ่งรวมถึงREGEXP_REPLACEได้รับการจัดเตรียมไว้แล้วใน MySQL 8.0 การแสดงผลนี้เป็นการอ่านที่ไม่จำเป็นเว้นแต่คุณจะถูกบังคับให้ใช้เวอร์ชันก่อนหน้า


อัปเดต 1:ทำให้สิ่งนี้กลายเป็นโพสต์บล็อก: http://stevettt.blogspot.co.uk/2018/02/a-mysql-regular-expression-replace.html


ต่อไปนี้จะขยายตามฟังก์ชั่นที่จัดทำโดย Rasika Godawatteแต่ลากผ่านสตริงย่อยที่จำเป็นทั้งหมดแทนที่จะทดสอบตัวอักขระเดียว:

-- ------------------------------------------------------------------------------------
-- USAGE
-- ------------------------------------------------------------------------------------
-- SELECT reg_replace(<subject>,
--                    <pattern>,
--                    <replacement>,
--                    <greedy>,
--                    <minMatchLen>,
--                    <maxMatchLen>);
-- where:
-- <subject> is the string to look in for doing the replacements
-- <pattern> is the regular expression to match against
-- <replacement> is the replacement string
-- <greedy> is TRUE for greedy matching or FALSE for non-greedy matching
-- <minMatchLen> specifies the minimum match length
-- <maxMatchLen> specifies the maximum match length
-- (minMatchLen and maxMatchLen are used to improve efficiency but are
--  optional and can be set to 0 or NULL if not known/required)
-- Example:
-- SELECT reg_replace(txt, '^[Tt][^ ]* ', 'a', TRUE, 2, 0) FROM tbl;
DROP FUNCTION IF EXISTS reg_replace;
DELIMITER //
CREATE FUNCTION reg_replace(subject VARCHAR(21845), pattern VARCHAR(21845),
  replacement VARCHAR(21845), greedy BOOLEAN, minMatchLen INT, maxMatchLen INT)
RETURNS VARCHAR(21845) DETERMINISTIC BEGIN 
  DECLARE result, subStr, usePattern VARCHAR(21845); 
  DECLARE startPos, prevStartPos, startInc, len, lenInc INT;
  IF subject REGEXP pattern THEN
    SET result = '';
    -- Sanitize input parameter values
    SET minMatchLen = IF(minMatchLen < 1, 1, minMatchLen);
    SET maxMatchLen = IF(maxMatchLen < 1 OR maxMatchLen > CHAR_LENGTH(subject),
                         CHAR_LENGTH(subject), maxMatchLen);
    -- Set the pattern to use to match an entire string rather than part of a string
    SET usePattern = IF (LEFT(pattern, 1) = '^', pattern, CONCAT('^', pattern));
    SET usePattern = IF (RIGHT(pattern, 1) = '$', usePattern, CONCAT(usePattern, '$'));
    -- Set start position to 1 if pattern starts with ^ or doesn't end with $.
    IF LEFT(pattern, 1) = '^' OR RIGHT(pattern, 1) <> '$' THEN
      SET startPos = 1, startInc = 1;
    -- Otherwise (i.e. pattern ends with $ but doesn't start with ^): Set start pos
    -- to the min or max match length from the end (depending on "greedy" flag).
    ELSEIF greedy THEN
      SET startPos = CHAR_LENGTH(subject) - maxMatchLen + 1, startInc = 1;
    ELSE
      SET startPos = CHAR_LENGTH(subject) - minMatchLen + 1, startInc = -1;
    END IF;
    WHILE startPos >= 1 AND startPos <= CHAR_LENGTH(subject)
      AND startPos + minMatchLen - 1 <= CHAR_LENGTH(subject)
      AND !(LEFT(pattern, 1) = '^' AND startPos <> 1)
      AND !(RIGHT(pattern, 1) = '$'
            AND startPos + maxMatchLen - 1 < CHAR_LENGTH(subject)) DO
      -- Set start length to maximum if matching greedily or pattern ends with $.
      -- Otherwise set starting length to the minimum match length.
      IF greedy OR RIGHT(pattern, 1) = '$' THEN
        SET len = LEAST(CHAR_LENGTH(subject) - startPos + 1, maxMatchLen), lenInc = -1;
      ELSE
        SET len = minMatchLen, lenInc = 1;
      END IF;
      SET prevStartPos = startPos;
      lenLoop: WHILE len >= 1 AND len <= maxMatchLen
                 AND startPos + len - 1 <= CHAR_LENGTH(subject)
                 AND !(RIGHT(pattern, 1) = '$' 
                       AND startPos + len - 1 <> CHAR_LENGTH(subject)) DO
        SET subStr = SUBSTRING(subject, startPos, len);
        IF subStr REGEXP usePattern THEN
          SET result = IF(startInc = 1,
                          CONCAT(result, replacement), CONCAT(replacement, result));
          SET startPos = startPos + startInc * len;
          LEAVE lenLoop;
        END IF;
        SET len = len + lenInc;
      END WHILE;
      IF (startPos = prevStartPos) THEN
        SET result = IF(startInc = 1, CONCAT(result, SUBSTRING(subject, startPos, 1)),
                        CONCAT(SUBSTRING(subject, startPos, 1), result));
        SET startPos = startPos + startInc;
      END IF;
    END WHILE;
    IF startInc = 1 AND startPos <= CHAR_LENGTH(subject) THEN
      SET result = CONCAT(result, RIGHT(subject, CHAR_LENGTH(subject) + 1 - startPos));
    ELSEIF startInc = -1 AND startPos >= 1 THEN
      SET result = CONCAT(LEFT(subject, startPos), result);
    END IF;
  ELSE
    SET result = subject;
  END IF;
  RETURN result;
END//
DELIMITER ;

การสาธิต

การสาธิต Rextester

ข้อ จำกัด

  1. วิธีนี้แน่นอนว่าจะใช้เวลาสักครู่เมื่อสตริงหัวเรื่องมีขนาดใหญ่ อัปเดต:ตอนนี้ได้เพิ่มพารามิเตอร์ความยาวการจับคู่ขั้นต่ำและสูงสุดเพื่อปรับปรุงประสิทธิภาพเมื่อทราบแล้ว (ศูนย์ = ไม่ทราบ / ไม่ จำกัด )
  2. มันจะไม่อนุญาตให้มีการเปลี่ยนตัวของ backreferences (เช่น\1, \2 ฯลฯ ) เพื่อแทนที่กลุ่มจับ หากจำเป็นต้องใช้ฟังก์ชั่นนี้โปรดดูคำตอบที่พยายามให้วิธีแก้ปัญหาโดยการปรับปรุงฟังก์ชั่นเพื่อให้การค้นหารองและแทนที่ภายในการแข่งขันที่พบแต่ละครั้ง (ค่าใช้จ่ายของความซับซ้อนที่เพิ่มขึ้น)
  3. หาก^และ / หรือ$ใช้ในรูปแบบจะต้องอยู่ที่จุดเริ่มต้นและจุดสิ้นสุดตามลำดับ - เช่นรูปแบบเช่น(^start|end$)ไม่ได้รับการสนับสนุน
  4. มีการตั้งค่าสถานะ "โลภ" เพื่อระบุว่าการจับคู่โดยรวมควรเป็นโลภหรือไม่โลภ ไม่สนับสนุนการรวมการจับคู่โลภและขี้เกียจภายในนิพจน์ทั่วไป (เช่นa.*?b.*)

ตัวอย่างการใช้งาน

ฟังก์ชันนี้ถูกใช้เพื่อตอบคำถาม StackOverflow ต่อไปนี้:


7

คุณสามารถทำมันได้ ... แต่มันไม่ฉลาดนัก ... นี่มันเป็นเรื่องที่กล้าหาญอย่างที่ฉันจะลอง ... เท่าที่ RegEx จะสนับสนุนคุณได้ดีกว่าการใช้ Perl หรือสิ่งที่คล้ายกัน

UPDATE db.tbl
SET column = 
CASE 
WHEN column REGEXP '[[:<:]]WORD_TO_REPLACE[[:>:]]' 
THEN REPLACE(column,'WORD_TO_REPLACE','REPLACEMENT')
END 
WHERE column REGEXP '[[:<:]]WORD_TO_REPLACE[[:>:]]'

1
ไม่นั่นไม่ได้ผล ลองนึกภาพคอลัมน์ของคุณมี 'asdfWORD_TO_REPLACE WORD_TO_REPLACE "วิธีการของคุณจะส่งผลให้' asdfREPLACEMENT REPLACEMENT" ซึ่งคำตอบที่ถูกต้องคือ "asdfWORD_TO_REPLACE REPLACEMENT"
Ryan Shillington

1
@ Ryan ... นั่นเป็นเหตุผลว่าทำไมฉันถึงบอกว่ามันไม่ฉลาดมาก ... ในกรณีที่คุณให้สิ่งนี้จะล้มเหลวอย่างแน่นอน ในระยะสั้นมันเป็นความคิดที่ดีที่จะใช้โครงสร้าง 'เหมือน regex' ยิ่งแย่กว่าเดิม ... ถ้าคุณทิ้งที่ที่ค่าทั้งหมดของคุณจะเป็นโมฆะ ...
Eddie B

1
ไรอันที่จริงในกรณีนี้คุณไม่ถูกต้องเป็นเครื่องหมายเท่านั้นที่จะพบว่าตรงกับคำความยาวเป็นศูนย์ 'ขอบเขตคำพูดเพื่อให้เฉพาะกับเขตแดนก่อนและหลังคำว่าจะตรงกับ ... มันยังคงเป็นความคิดที่ดี แต่ ...
Eddie B

6

เราสามารถใช้เงื่อนไข IF ในแบบสอบถามแบบใช้เลือกข้อมูลได้ดังนี้:

สมมติว่าทุกอย่างที่มี "ABC", "ABC1", "ABC2", "ABC3", ... เราต้องการแทนที่ด้วย "ABC" จากนั้นใช้เงื่อนไข REGEXP และ IF () ในแบบสอบถาม SELECT เราสามารถบรรลุสิ่งนี้ .

ไวยากรณ์:

SELECT IF(column_name REGEXP 'ABC[0-9]$','ABC',column_name)
FROM table1 
WHERE column_name LIKE 'ABC%';

ตัวอย่าง:

SELECT IF('ABC1' REGEXP 'ABC[0-9]$','ABC','ABC1');

สวัสดีขอขอบคุณสำหรับคำแนะนำ ฉันได้ลองทำสิ่งที่คล้ายกัน แต่ประสิทธิภาพของชุดข้อมูลของฉันไม่เป็นที่น่าพอใจ สำหรับชุดเล็ก ๆ สิ่งนี้อาจเป็นไปได้
Piskvor ออกจากอาคาร

3

ด้านล่างโดยทั่วไปจะพบการแข่งขันครั้งแรกจากทางซ้ายแล้วแทนที่การเกิดขึ้นทั้งหมดของมัน (ทดสอบมา )

การใช้งาน:

SELECT REGEX_REPLACE('dis ambiguity', 'dis[[:space:]]*ambiguity', 'disambiguity');

การดำเนินงาน:

DELIMITER $$
CREATE FUNCTION REGEX_REPLACE(
  var_original VARCHAR(1000),
  var_pattern VARCHAR(1000),
  var_replacement VARCHAR(1000)
  ) RETURNS
    VARCHAR(1000)
  COMMENT 'Based on https://techras.wordpress.com/2011/06/02/regex-replace-for-mysql/'
BEGIN
  DECLARE var_replaced VARCHAR(1000) DEFAULT var_original;
  DECLARE var_leftmost_match VARCHAR(1000) DEFAULT
    REGEX_CAPTURE_LEFTMOST(var_original, var_pattern);
    WHILE var_leftmost_match IS NOT NULL DO
      IF var_replacement <> var_leftmost_match THEN
        SET var_replaced = REPLACE(var_replaced, var_leftmost_match, var_replacement);
        SET var_leftmost_match = REGEX_CAPTURE_LEFTMOST(var_replaced, var_pattern);
        ELSE
          SET var_leftmost_match = NULL;
        END IF;
      END WHILE;
  RETURN var_replaced;
END $$
DELIMITER ;

DELIMITER $$
CREATE FUNCTION REGEX_CAPTURE_LEFTMOST(
  var_original VARCHAR(1000),
  var_pattern VARCHAR(1000)
  ) RETURNS
    VARCHAR(1000)
  COMMENT '
  Captures the leftmost substring that matches the [var_pattern]
  IN [var_original], OR NULL if no match.
  '
BEGIN
  DECLARE var_temp_l VARCHAR(1000);
  DECLARE var_temp_r VARCHAR(1000);
  DECLARE var_left_trim_index INT;
  DECLARE var_right_trim_index INT;
  SET var_left_trim_index = 1;
  SET var_right_trim_index = 1;
  SET var_temp_l = '';
  SET var_temp_r = '';
  WHILE (CHAR_LENGTH(var_original) >= var_left_trim_index) DO
    SET var_temp_l = LEFT(var_original, var_left_trim_index);
    IF var_temp_l REGEXP var_pattern THEN
      WHILE (CHAR_LENGTH(var_temp_l) >= var_right_trim_index) DO
        SET var_temp_r = RIGHT(var_temp_l, var_right_trim_index);
        IF var_temp_r REGEXP var_pattern THEN
          RETURN var_temp_r;
          END IF;
        SET var_right_trim_index = var_right_trim_index + 1;
        END WHILE;
      END IF;
    SET var_left_trim_index = var_left_trim_index + 1;
    END WHILE;
  RETURN NULL;
END $$
DELIMITER ;

3

ฉันคิดว่ามีวิธีง่าย ๆ ในการบรรลุเป้าหมายและทำงานได้ดีสำหรับฉัน

ในการเลือกแถวโดยใช้ REGEX

SELECT * FROM `table_name` WHERE `column_name_to_find` REGEXP 'string-to-find'

หากต้องการอัปเดตแถวโดยใช้ REGEX

UPDATE `table_name` SET column_name_to_find=REGEXP_REPLACE(column_name_to_find, 'string-to-find', 'string-to-replace') WHERE column_name_to_find REGEXP 'string-to-find'

การอ้างอิง REGEXP: https://www.geeksforgeeks.org/mysql-regular-expressions-regexp/


ขอบคุณ :) มันเป็นไปได้ที่จะทำอย่างง่ายดายตั้งแต่เวอร์ชั่น 8
Piskvor ออกจากอาคารเมื่อ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.