2014-01-22 72 views
3

我所遇到下面的情景,搜索字符串特定字符 - 甲骨文

我有一个列名Broker_name为数不多的价值观它是'tpt Broker','Mark iii', 'Davidtpt'

这些价值最终输出应该是'TPT Broker', 'Mark III','Davidtpt'基本上我需要一些CAPS预定值的字符串说TPT自带的尾随空格,罗马字母等。

,所以我创建了一个查找表其中有

Column1 Column2 
tpt  TPT 
iii  III 

请问我可以让我知道如何检查特定字符是否存在于字符串中,然后在桌面上查找。基于那个?

+0

一个有趣的挑战。我将交叉连接到查找表并使用自定义聚合函数来执行替换。有点麻烦,也许有人想出了一些聪明... –

+0

严格地说,你已经打破了1NF。我会研究如何规范化数据库(将字段拆分为原子组成部分)。之后,你的任务应该可以通过一个相当简单的JOIN来实现。 –

回答

0

这有些困难,因为它需要不区分大小写(例如iIitpT)。通常情况下,您只需使用UPPER(),但您想保留其余列的大小写。它也必须替换许多不同的“不正确的”字母。最后,你不希望像xxxtpt这样的东西被拿起来,如果你不能通过空格(因为它可能在开始或结束时),这很困难。我不确定你的最终目标是什么。我可以想到两个:

  1. 你只是想要一个查询来正确地格式化结果。
  2. 你想更新任何包含此值的值。

无论哪种方式,这是我可以想出的最简单的解决方案(虽然补救)。您必须考虑所有不正确的病例组合(例如:tpt, tpT, tPt, tPT, Tpt, TPt)。这是一个有点蛮力,但由于缺乏时间和简单性(尤其是如果它只是少数情况下),这会工作:

代码:

Select 
Trim(
    Replace(
    Replace(
    Replace(
    Replace(
    Replace(
    --note the ' ' are added so we can search for a isolated instance of 
    --' tpt ' at the beginning or end of lines, as well as inbetween 
    -- these space get Trim()'d at in the end of processing everything. 
    Replace(' ' || test_t.text || ' ', ' tpt ', ' TPT ') 
            , ' tpT ', ' TPT ') 
            , ' tPt ', ' TPT ') 
            --etc... 
            , ' iii ', ' III ') 
            --etc... 
            , ' Iii ', ' III ') 
            , ' IIi ', ' III ') 
) 
as text 

--poor man's way of creating test tables 
From 
(
    Select 'tpt Broker' as text From dual UNION ALL 
    Select 'Mark iii' as text From dual UNION ALL 
    Select 'Davidtpt' as text From dual 
) test_t 

结果:

TPT Broker 
Mark III 
Davidtpt 

这几乎是穷人的方式。如果这是一个长期的问题,我相信有更好的解决方案,但如果您的数据清理容易,这可能会奏效。您也可以尝试使用REGEXP_REPLACEINSTR的组合。如果我想到更好的东西,我会更新这篇文章。

编辑:

爱,我知道必须有更好的方法。使用REGEXP_REPLACE可以简化这一点。我无法获得“不区分大小写”的查询工作(可能忽略了某些内容)。同样的方法,但这里是一个真正的体面的解决办法:

Select 
    Trim(
     REGEXP_REPLACE(
     REGEXP_REPLACE(
      ' ' || text || ' ' , ' [tT][pP][tT] ', ' TPT ') 
           , ' [iI][iI][iI] ', ' III ') 
     ) as text 
From 
(
    Select 'tPt Broker' as text From dual UNION ALL 
    Select 'Mark iii' as text From dual UNION ALL 
    Select 'Davidtpt' as text From dual 
) test_t 
1

最后我设法处理它与模式条款的一点帮助:

SELECT id, broker_name FROM (
    SELECT id, broker_name, rn, val, replacement 
    FROM brokers CROSS JOIN (SELECT rownum AS rn, val, replacement FROM lookup) 
    MODEL 
    PARTITION BY (id) 
    DIMENSION BY (rn) 
    MEASURES (val, replacement, broker_name) 
    RULES (
     broker_name[ANY] = regexp_replace(nvl(broker_name[CV()-1], broker_name[CV()]), 
             '(^|.*\W)' || val[CV()] || '(\W.*|$)', 
             '\1' || replacement[CV()] || '\2') 
    ) 
) 
WHERE rn = (SELECT count(*) FROM lookup) 
ORDER BY id, broker_name; 

基本上它具有下列功能:

  1. 查找表中的项目数
  2. 执行代理之间的交叉连接并查找
  3. 对于它通过查找值迭代并使得更换每个代理(在有些奇怪的正则表达式可以确保只有整个单词被替换)
  4. 最后所花费的最后一行仅每代理,它包含所有的替换后的值已经取得

这是SQL Fiddle

+0

你好Kombajin, 当我试图用这个数据“MARK III/TPT”它没有工作。 小提琴的位置: - http://sqlfiddle.com/#!4/586f0/1 – Ragav

+0

这是因为“/”,我只是用空间(\ S)作为字分隔符。但是,我们也可以使用任何非字母数字(\ W),检查出更新的查询(也不甘示弱这里:http://sqlfiddle.com/#!4/586f0/4) –

+0

进程似乎运行了很时间。另外,我们需要在另一列上执行类似的查找操作,我们可以在附加的查询中结合这一点吗?考虑源表中的30,000条记录和查找表中的8条记录。我认为这个过程可能会耗尽时间。还有其他选择吗?像使用光标。 – Ragav