SQL 使用计数,在同一单元格中多次使用相同的 "Like"

SQL using Count, with same "Like" multiple times in same cell

我想统计 BNxxxx 在评论单元格中被评论了多少次。到目前为止,我可以让每个单元格都被计数一次,但是在一个包含 BNxxxx 的单元格中可能会有多个注释。

例如,这个:

------- 
BN0012
------- 
BN0012
------- 
BN0012
BN0123
-------

应该显示 BN0012 输出 3 次和 BN0123 一次。相反,我只得到了 3 次 BN0012。

这是我的代码:

select COMMENTS, count(*) as TOTAL 
from NOTE 
Where COMMENTS like '%BN%' AND CREATE_DATE between '01/1/2015' AND '11/03/2015'
group by COMMENTS
order by Total desc; 

有什么想法吗?

编辑

我的代码现在看起来像

select BRIDGE_NO, count(*)
from IACD_ASSET b join 
IACD_NOTE c
on c.COMMENTS like concat(concat('BN',b.BRIDGE_NO),'%')
Where c.CREATE_DATE between '01/1/2015' AND '11/03/2015' AND length(b.BRIDGE_NO) > 1 
group by b.BRIDGE_NO
order by count(*);

问题在于 BN44 与 BN4455 相同.. 尝试过 concat(concat('BN',b.BRIDGE_NO),'_') 结果一无所获,我有什么想法可以得到完全喜欢

你有问题。让我假设你有一个你关心的所有已知 BN 值的 table。然后你可以这样做:

select bn.fullbn, count(*)
from tableBN bn join
     comments c
     on c.comment like ('%' || bn.fullbn || '%')
group by bn.fullbn;

这个的性能可能会很慢。

如果您碰巧在评论字段中存储了事物列表,那么这是一个非常糟糕的主意。您不应该将列表存储在字符串中;你应该使用路口 table.

尝试在 select 语句中使用 distinct 关键字,为评论引入唯一值。像这样:

select distinct COMMENTS, count(*) as TOTAL 
from NOTE 
Where COMMENTS like '%BN%' AND CREATE_DATE between '01/1/2015' AND    
'11/03/2015'
group by COMMENTS
order by Total desc; 

我假设你的 COMMENTS table 有一个主键列(比如 comment_id)或者至少 comments 不是CLOB。如果它是 CLOB,那么您将无法在该列上使用 GROUP BY

您甚至无需查找 table 的 BN.... 值即可完成此操作。不保证性能:

WITH d1 AS (
    SELECT 1 AS comment_id, 'BN0123 is a terrible thing BN0121 also BN0000' AS comments
         , date'2015-01-03' AS create_date
      FROM dual
     UNION ALL
    SELECT 2 AS comment_id, 'BN0125 is a terrible thing BN0120 also BN1000' AS comments
         , date'2015-02-03' AS create_date
      FROM dual
)
SELECT comment_id, comments, COUNT(*) AS total FROM (
    SELECT comment_id, comments, TRIM(REGEXP_SUBSTR(comments, '(^|\s)BN\d+(\s|$)', 1, LEVEL, 'i')) AS bn
      FROM d1
     WHERE create_date >= date'2015-01-01'
       AND create_date < date'2015-11-04'
   CONNECT BY REGEXP_SUBSTR(comments, '(^|\s)BN\d+(\s|$)', 1, LEVEL, 'i') IS NOT NULL
       AND PRIOR comment_id = comment_id
       AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL
) GROUP BY comment_id, comments;

请注意,我更正了您的过滤器:

CREATE_DATE between '01/1/2015' AND '11/03/2015'

首先,您应该使用 ANSI 日期文字(例如 date'2015-01-01');其次,对日期使用 BETWEEN 通常不是一个好主意,因为 Oracle DATE 值包含时间部分。所以这应该改写为:

    create_date >= date'2015-01-01'
AND create_date < date'2015-11-04'

请注意,较晚的日期是 11 月 4,以确保我们收集到所有可能在 11 月 3 发表的评论。

如果你想在不聚合计数的情况下查看匹配的评论,请执行以下操作(基本上去掉外部查询):

WITH d1 AS (
    SELECT 1 AS comment_id, 'BN0123 is a terrible thing BN0121 also BN0000' AS comments
         , date'2015-01-03' AS create_date
      FROM dual
     UNION ALL
    SELECT 2 AS comment_id, 'BN0125 is a terrible thing BN0120 also BN1000' AS comments
         , date'2015-02-03' AS create_date
      FROM dual
)
SELECT comment_id, comments, TRIM(REGEXP_SUBSTR(comments, '(^|\s)BN\d+(\s|$)', 1, LEVEL, 'i')) AS bn
  FROM d1
 WHERE create_date >= date'2015-01-01'
   AND create_date < date'2015-11-04'
CONNECT BY REGEXP_SUBSTR(comments, '(^|\s)BN\d+(\s|$)', 1, LEVEL, 'i') IS NOT NULL
   AND PRIOR comment_id = comment_id
   AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL;

鉴于对您的问题的编辑,我认为您需要如下内容:

SELECT b.bridge_no, COUNT(*) AS comment_cnt
  FROM iacd_asset b INNER JOIN iacd_note c
    ON REGEXP_LIKE(c.comments, '(^|\W)BN' || b.bridge_no || '(\W|$)', 'i')
 WHERE c.create_dt >= date'2015-01-01'
   AND c.create_dt < date'2015-03-12' -- It just struck me that your dates are dd/mm/yyyy
   AND length(b.bridge_no) > 1
 GROUP BY b.bridge_no
 ORDER BY comment_cnt;

请注意,我在上面的正则表达式中使用 \W 而不是我之前使用的 \s 以确保它捕获诸如 BN1234/BN6547.

之类的内容