2011-03-08 125 views
1

在下表中,我如何匹配'FG2-4G4T5',以便第一个返回的行是最匹配的(这将是'FG2-4G')?匹配最好的正则表达式

part_match 
^FG2|^FF2|^FF3-S|^FF4-GR 
^FG2-4G 
^FG2 
FG2-RGST 

下面的查询不会在这种情况下工作,因为“^FG2|^FF2|^FF3-S|^FF4-GR”具有更大的长度:

SELECT * FROM parts WHERE 'FG2-4G4T5' REGEXP part_match ORDER BY length(part_match) DEC 

任何帮助将不胜感激。提前致谢。

+0

哎呀,对不起@hsz吹你的编辑...我会放弃它。 – Donut 2011-03-08 19:37:40

回答

0

假设你part_match的是一个总的形式^ XXXX和可选大小相等的^ YYYY |^ZZZZ | ...

SELECT * FROM parts 
WHERE 'FG2-4G4T5' REGEXP part_match 
ORDER BY instr(concat(part_match,'|'),'|') DEC 

这会给你的最长前缀匹配。

为了解决FULL匹配的夹杂物,需要一断部分的匹配的长度,所以,

SELECT * FROM parts 
WHERE 'FG2-4G4T5' REGEXP part_match 
ORDER BY CASE WHEN part_match LIKE '^%' THEN -1 else 0 end + 
     instr(concat(part_match,'|'),'|') DEC 

为了解决REGEX涉及不等长度,例如多段^YYYY|^Z|ABC,你首先需要找到打破了为多行

part_match | single_part 
^YYYY|^Z|ABC ^YYYY 
^YYYY|^Z|ABC ^Z 
^YYYY|^Z|ABC ABC 

然后通过REGEXP引用single_part早在回答part_match的功能。这是不重要的,但可以通过Numbers表格和SUBSTR和INSTR的合理使用来实现。

创建一个数字表(运行此一次):

DROP PROCEDURE IF EXISTS CreateNumbersTable; 

delimiter // 
CREATE PROCEDURE CreateNumbersTable() 
    LANGUAGE SQL 
    NOT DETERMINISTIC 
    CONTAINS SQL 
    SQL SECURITY DEFINER 
    COMMENT '' 
BEGIN 
    drop table if exists Numbers; 
    create table Numbers (N int primary key); 

    SET @x := 0; 
    REPEAT 
    insert into Numbers values (@x); 
    SET @x := @x + 1; 
    UNTIL @x > 999 END REPEAT; 
END// 
delimiter ; 

CALL CreateNumbersTable; 

DROP PROCEDURE CreateNumbersTable; 

然后你可以使用此查询

select p.* 
# ,substr(p.part_match, N.N+1, locate('|', concat(p.part_match,'|'), N.N+2) -N.N -1) 
# ,length(substr(p.part_match, N.N+1, locate('|', concat(p.part_match,'|'), N.N+2) -N.N -1)) 
from parts p 
inner join numbers N on N.N between 0 and length(p.part_match) 
    and ((N.N = 0) or (substr(p.part_match, N.N, 1) = '|')) 
WHERE 'FG2-RGST' REGEXP p.part_match 
    and 'FG2-RGST' REGEXP substr(p.part_match, N.N+1, locate('|', concat(p.part_match,'|'), N.N+2) -N.N -1) 
order by length(substr(p.part_match, N.N+1, locate('|', concat(p.part_match,'|'), N.N+2) -N.N -1)) DESC 

取消注释行2和3,看part_match的它匹配的零件。

+0

谢谢。也有完整的部分匹配(即'FG2-4G4T5'也可能在表格中) – 2011-03-08 20:22:16

+0

它们的尺寸也不相同 – 2011-03-08 20:23:50

+0

是的抱歉.....这是一张巨大的桌子,从一开始就设计得很糟糕。现在我知道公司发展很快;这现在是一个问题。我想避免使用C++来解决这个问题。 – 2011-03-08 20:34:19

2

有时K.I.S.S.解决方案最好。保留另一列,列出模式匹配的文本的实际长度?

part_match   part_match_length 
====================================== 
^FG2|^FF2|^FF3|^FF4 3 
^FG2-4G    6 
^FG2     3 

,因此...

SELECT * FROM parts 
WHERE 'FG2-4G4T5' REGEXP part_match 
ORDER BY part_match_length DEC 

技术上,第二列甚至没有到一定要长 - 只是某种给定模式如何很好的匹配提供指示。

+0

Thanks.I can not have the thousands and millions millions of entries – 2011-03-08 20:21:21

+0

如果你能以编程的方式确定长度(例如 - 选择每个模式,分割'|',并寻找最长的子字符串),那么你可以有一个脚本来为您创建专栏。仅仅因为它是一个单独的列,并不意味着你必须手动输入。 – Amber 2011-03-08 20:28:09

+0

单个part_match可以包含多个长度,您需要确定“|||'的哪个组件是匹配的。此解决方案不起作用 – RichardTheKiwi 2011-03-08 20:36:34