Oracle SQL Regex匹配两个字段

jhkqcmku  于 12个月前  发布在  Oracle
关注(0)|答案(3)|浏览(121)

我有两个表在oracle sql与字段在每个我需要匹配和显示,如果它不匹配。单独表中的两个字段有各种格式,这并不理想,但情况就是如此。范例:
表1:
| ID|示例_字符串|示例_正则表达式_匹配|
| --|--|--|
| 1 |(0888DY:A001:B2:C3)|A1b2c3|
| 2 |(0888DY:A001:B3)|A1b3|
表2:
| ID|示例_字符串|示例_正则表达式_匹配|
| --|--|--|
| 1 |0888DY,A1:B2:C3| A1b2c3|
| 2 |0888DY,A1:B2| A1b2|
在上面的例子中,我希望ID 1在表之间匹配并被忽略,而ID 2被选择,因为它彼此不匹配。匹配的确定只是A后跟一个非零值,B后跟任何非零值,C后跟任何非零值,等等,所以在ID 1的情况下:A1 B2 C3.所有其他的东西,比如前缀0888 DY,逗号,括号,前导零,理想情况下都可以忽略。我假设我需要使用正则表达式来实现这一点,所以这里是我的开始:

SELECT a.ID, a.EXAMPLE_STRING, b.EXAMPLE_STRING
FROM Table1 a
INNER JOIN Table2 b
ON a.ID = b.ID
WHERE REGEX_REPLACE(a.EXAMPLE_STRING, regexhere) != REGEX_REPLACE(b.EXAMPLE_STRING, regexhere)
vktxenjb

vktxenjb1#

REGEXP_INSTR()对于判断两个字符串是否匹配相同的模式没有用处。它只是返回找到模式匹配的位置(就像INSTR()处理普通字符串一样)。
为了将A001转换为A1,您需要将REGEXP_REPLACE()沿着一个捕获组,以便可以删除前导零。
在比较之前,您还需要删除第一个:,之前的所有内容。

WHERE REGEXP_REPLACE(REGEXP_REPLACE(a.EXAMPLE_STRING, '^[^,:]*', ''), '[,:]([[:alpha:]])0*([[:digit:]]+)', '\1\2') != REGEXP_REPLACE(REGEXP_REPLACE(b.EXAMPLE_STRING, '^[^,:]*', ''), '[,:]([[:alpha:]])0*([[:digit:]]+)', '\1\2')
kcwpcxri

kcwpcxri2#

首先你提到的匹配模式我不知道为什么我不能理解它。你描述的方式,
匹配的确定只是A后跟一个非零值,B后跟任何非零值,C后跟任何非零值
这也不应该匹配表1的第1行,因为A后面跟着一些零,但在表2中不是这种情况。
如果这个答案对你没有帮助我需要更多的解释。
正如你提到的:
单独表中的两个字段有各种格式,这并不理想
一个想法是 * 尝试规范化这两个字段 *,以便那些不匹配的字段。看看这个:

-- CTEs to normalize the strings 
--and REGEXP_REPLACE to remove all non-alphanumeric characters from EXAMPLE_STRING
WITH NormalizedTable1 AS (
  SELECT ID, REGEXP_REPLACE(EXAMPLE_STRING, '[^A-Za-z0-9]', '') AS NormalizedString
  FROM Table1
),
NormalizedTable2 AS (
  SELECT ID, REGEXP_REPLACE(EXAMPLE_STRING, '[^A-Za-z0-9]', '') AS NormalizedString
  FROM Table2
)
-- Finally, join the normalized tables and select non-matching records
SELECT t1.ID, t1.EXAMPLE_STRING AS Table1String, t2.EXAMPLE_STRING AS Table2String
FROM NormalizedTable1 t1
INNER JOIN NormalizedTable2 t2 ON t1.ID = t2.ID
WHERE t1.NormalizedString != t2.NormalizedString;

您应该非常小心地选择用于规范化的RegEx,以避免意外。
正如我所说的,我真的不能理解你的问题的那一部分,所以我的RegEx可能不会是一个确切的解决你的问题
祝你好运!

qnzebej0

qnzebej03#

根据所提供的数据以及您在M. Pour的回答(“* 本质上,我希望规范化/匹配只在字母A-C(不管前导零和前缀)和它之后但在下一个字母 * 之前的非零数字上”)一个选项可以根本不使用regexp。
创建CTE,它将转换您的示例数据以使其模式化:

WITH        --  Sample Data
    tbl_1 (ID, EXAMPLE_STRING) AS
        (   Select  1,  '(0888DY:A001:B2:C3)' From Dual Union All
        Select  2,  '(0888DY:A001:B3)' From Dual 
        ),
    tbl_2 (ID, EXAMPLE_STRING) AS
        (   Select  1,  '0888DY,A1:B2:C3' From Dual Union All
        Select  2,  '0888DY,A1:B2' From Dual 
        ),
  transformed AS
    (   Select        t1.ID, 
                    t1.EXAMPLE_STRING "T1_STRING_ORIGINAL",
                    t2.EXAMPLE_STRING "T2_STRING_ORIGINAL",
                    Replace(SubStr( Replace(Replace(Replace(t1.EXAMPLE_STRING, '(', ''), ')', ''), ',', ':')
                          , InStr(Replace(Replace(Replace(t1.EXAMPLE_STRING, '(', ''), ')', ''), ',', ':') || ':', ':', 1, 1) + 1 ), ':', '') "T1_TO_MATCH",  
                    -- 
                    Replace(SubStr( Replace(Replace(Replace(t2.EXAMPLE_STRING, '(', ''), ')', ''), ',', ':')
                          , InStr(Replace(Replace(Replace(t2.EXAMPLE_STRING, '(', ''), ')', ''), ',', ':') || ':', ':', 1, 1) + 1 ), ':', '') "T2_TO_MATCH"
        From            tbl_1 t1
        Inner Join  tbl_2 t2 ON(t2.ID = t1.ID)
    ),
--
--  Result for transformed CTE
--
--          ID T1_STRING_ORIGINAL  T2_STRING_ORIGI T1_TO_MATCH    T2_TO_MATCH      
--  ---------- ------------------- --------------- -------------- -----------------
--           1 (0888DY:A001:B2:C3) 0888DY,A1:B2:C3 A001B2C3       A1B2C3           
--           2 (0888DY:A001:B3)    0888DY,A1:B2    A001B3         A1B2

**注意:**以上代码删除了不需要进一步处理的字符,如圆括号和逗号,并切断了第一个元素。请注意,这适用于提供的示例数据,如果在您的真实的数据中还有其他一些此类字符,您可能也需要处理它们。

应该使用另一个CTE对生成的数据集进行进一步调整,然后您就可以获得预期的结果

matches AS
    (   Select  t.ID, T1_STRING_ORIGINAL, T2_STRING_ORIGINAL, 
                Case When InStr(t.T1_TO_MATCH, 'A') > 0 Then SubStr( t.T1_TO_MATCH, 1, InStr(t.T1_TO_MATCH, 'A')) End|| 
                  Case When InStr(t.T1_TO_MATCH, 'A') > 0 Then CAST(SubStr(t.T1_TO_MATCH, InStr(t.T1_TO_MATCH, 'A') + 1, Case When InStr(t.T1_TO_MATCH, 'B') > 0 Then InStr(t.T1_TO_MATCH, 'B') Else 9999 End - InStr(t.T1_TO_MATCH, 'A') - 1) as Number DEFAULT 0 ON CONVERSION ERROR) End ||
                Case When InStr(t.T1_TO_MATCH, 'B') > 0 Then SubStr( t.T1_TO_MATCH, InStr(t.T1_TO_MATCH, 'B'), 1) End || 
                  Case When InStr(t.T1_TO_MATCH, 'B') > 0 Then CAST(SubStr(t.T1_TO_MATCH, InStr(t.T1_TO_MATCH, 'B') + 1,  Case When InStr(t.T1_TO_MATCH, 'C') > 0 Then InStr(t.T1_TO_MATCH, 'C') Else 9999 End - InStr(t.T1_TO_MATCH, 'B') - 1) as Number DEFAULT 0 ON CONVERSION ERROR) End || 
                Case When InStr(t.T1_TO_MATCH, 'C') > 0 Then SubStr( t.T1_TO_MATCH, InStr(t.T1_TO_MATCH, 'C'), 1) End || 
                  Case When InStr(t.T1_TO_MATCH, 'C') > 0 Then CAST(SubStr(t.T1_TO_MATCH, InStr(t.T1_TO_MATCH, 'C') + 1) as Number DEFAULT 0 ON CONVERSION ERROR)  End
                "T1_TO_MATCH",
                --
                Case When InStr(t.T2_TO_MATCH, 'A') > 0 Then SubStr( t.T2_TO_MATCH, 1, InStr(t.T2_TO_MATCH, 'A')) End|| 
                  Case When InStr(t.T2_TO_MATCH, 'A') > 0 Then CAST(SubStr(t.T2_TO_MATCH, InStr(t.T2_TO_MATCH, 'A') + 1,  Case When InStr(t.T2_TO_MATCH, 'B') > 0 Then InStr(t.T2_TO_MATCH, 'B') Else 9999 End - InStr(t.T2_TO_MATCH, 'A') - 1) As Number DEFAULT 0 ON CONVERSION ERROR) End ||
                Case When InStr(t.T2_TO_MATCH, 'B') > 0 Then SubStr( t.T2_TO_MATCH, InStr(t.T2_TO_MATCH, 'B'), 1) End || 
                  Case When InStr(t.T2_TO_MATCH, 'B') > 0 Then CAST(SubStr(t.T2_TO_MATCH, InStr(t.T2_TO_MATCH, 'B') + 1,  Case When InStr(t.T2_TO_MATCH, 'C') > 0 Then InStr(t.T2_TO_MATCH, 'C') Else 9999 End - InStr(t.T2_TO_MATCH, 'B') - 1) as Number DEFAULT 0 ON CONVERSION ERROR) End || 
                Case When InStr(t.T2_TO_MATCH, 'C') > 0 Then SubStr( t.T2_TO_MATCH, InStr(t.T2_TO_MATCH, 'C'), 1) End || 
                  Case When InStr(t.T1_TO_MATCH, 'C') > 0 Then CAST(SubStr(t.T2_TO_MATCH, InStr(t.T2_TO_MATCH, 'C') + 1) as Number DEFAULT 0 ON CONVERSION ERROR) End
                "T2_TO_MATCH"
         From   transformed t 
    )    
--
--  Result for matches CTE
--
--          ID T1_STRING_ORIGINAL  T2_STRING_ORIGI T1_TO_MATCH          T2_TO_MATCH         
--  ---------- ------------------- --------------- -------------------- --------------------
--           1 (0888DY:A001:B2:C3) 0888DY,A1:B2:C3 A1B2C3               A1B2C3              
--           2 (0888DY:A001:B3)    0888DY,A1:B2    A1B3                 A1B2     

--  M a i n   S Q L           
SELECT  ID, T1_STRING_ORIGINAL, T2_STRING_ORIGINAL
FROM    matches
WHERE T1_TO_MATCH != T2_TO_MATCH
--
--  R e s u l t :
--
--          ID T1_STRING_ORIGINAL  T2_STRING_ORIGINAL
--  ---------- ------------------- ------------------
--           2 (0888DY:A001:B3)    0888DY,A1:B2

如果这可以调整以处理您的实际数据-它应该比regexp快得多。

相关问题