3

我有一张表说 EMPLOYEE,它有一列 EMPLOYEE_NAME。
我想查看超过 5 条记录中的短语。
该短语可以是至少 3 个字符的任何内容。
例如,我的表看起来像这样

EMPLOYEE_NAME
User1
User2
User3
Client1
Client2
Client3
Use1
Aent1
Auser2
ent3

我想在输出中看到“Use”和“ent”,因为它们有 5 个或更多记录匹配。
所以基本上我想看到长度为 3 的字符序列出现在 5 个或更多记录中的任何位置。
让我解释一下我的情况,以便有人可以想到比这更好的解决方案。
我有一个 web 服务,它会在一些数据库中访问一个存储过程。
这个网络服务有一个字段(比如员工姓名),我们可以在其中进行通配符搜索。
这个网络服务还有另一个字段,我们可以在其中指定输出中的最大记录数。
因此,如果特定短语的搜索结果超过该数字,我将在响应中收到错误。
我需要找到可以给我该错误的测试数据。
sp 中使用的查询只是在搜索短语前后放置 % 并返回所有 d 条匹配记录
,我知道 sp 使用的数据库、表和列,并且可以直接运行任何查询。
上面解释的这个查询解决方案是我能想到的唯一解决方案。
由于已经是周末,我没有尝试以下答案,下周将尝试第一件事。
但与此同时,如果有人能提供另一个更好的角度来寻找解决方案,那就更好了。有什么想法吗?

4

3 回答 3

3

这是症结所在:

“该短语可以是至少 3 个字符的任何内容。”

我希望您的意思是您要扫描表格以查找可以包含三个或更多字符的给定搜索模式。这很容易

select employee_id
           , employee_name
from  ( 
    with data as 
        ( select employee_id
                 , employee_name
                 , case 
                     when instr(employee_name, '&search_pattern ) > 0 
                     then 1 
                   else 0 end as i
          from employees )
    select employee_id
           , employee_name
           , sum(i ) over () as cnt
    from data
    where i > 0 )
where cnt >= 5;

现在,如果您的意思是要扫描每个 EMPLOYEE_NAME,确定该文本中的每组字符,然后搜索所有其他行以查找这些模式的出现,那么祝您好运。我希望您拥有一台具有大量 RAM 和许多内核的服务器,因为您将需要大量的工作(或非常小的桌子!)。

从您的评论看来,后一种选择就是您想要的。因此,这是一个查询,它将识别代码中的所有三字符段。您可以使用它来生成搜索模式的提要,您可以将其输入到我在上面发布的查询中。

select employee_name, triple from (
    with data as ( select max(length(employee_name)) as mx from employee )
    select employee_name
           , substr(employee_name, level, ,3) as triple
    from employee
         , data
    connect by level <= data.mx )
where length(triple) = 3;

在现实生活中,您只想选择 DISTINCT 三元组,但我留下了另一列以提供结果的上下文。

扩展此解决方案以查找三个或更多字符的片段作为练习留给读者;)


“我希望找到一个简单的解决方案。令我惊讶的是,到目前为止没有人遇到这个问题。”

好吧,是时候醒来闻一闻咖啡了。 字符串操作的计算量很大. 人们花费如此多的时间和金钱开发数据库模式的原因是我们不必投入大量精力来扫描长字符串以查找特定模式。

您的情况与我们期望在任何数据库中找到的情况完全相反。这就是为什么没有预装解决方案的原因,更不用说简单的解决方案了。

于 2013-01-11T17:11:09.587 回答
1

要将名称拆分为 3 的短语,您可以使用SUBSTR(employee_name, x, 3),其中 x 必须从 1 运行到length(employee_name)-1

substr('Client1',1,3) Cli
substr('Client1',2,3) lie
substr('Client1',3,3) ien
substr('Client1',4,3) ent
substr('Client1',5,3) nt1

要生成这些位置,可以创建一个包含从 1 到最大值的数字的表。或者使用一点魔法并即时生成数字:

SELECT level AS x FROM dual CONNECT BY level < max;
1
2
...

结合起来,这将得到所有员工姓名中长度为 3 的所有短语:

SELECT id, substr(employee_name, x, 3) AS phrase
  FROM employee
  JOIN (SELECT level AS x FROM dual CONNECT BY level < 27) pos
    ON pos.x < length(employee_name)-1;
1 Use
1 ser
1 er1
...

现在我们只需要过滤掉出现在 5 行或更多行中的短语。这很容易通过以下方式完成GROUP BY phrase HAVING count(DISTINCT id) >= 5

SELECT phrase, count(distinct id)
  FROM (
        SELECT id, substr(employee_name, x, 3) AS phrase
          FROM employee
          JOIN (SELECT level AS x FROM dual CONNECT BY level < 27) pos
            ON pos.x < length(employee_name)-1
       )
 GROUP BY phrase
HAVING count(distinct id) >= 5;
ent 5

为什么“使用”应该出现在您的示例结果中?我只有4行?

于 2013-01-11T21:43:40.900 回答
1

就个人而言,我会使用一个管道行函数,它将为输入字符串中找到的每个三元组的输入 n 个记录中的每个字符串返回。使用此(表)函数,我将与 EMPLOYEE_NAME 与 group by 连接,并仅选择超过 5 个不同的员工姓名计数。如果您有兴趣可以给您一个代码示例。

于 2013-01-11T20:03:31.983 回答