【问题标题】:SQL using Count, with same "Like" multiple times in same cellSQL 使用 Count,在同一个单元格中多次使用相同的“Like”
【发布时间】:2015-03-11 00:48:29
【问题描述】:

我正在尝试计算 BNxxxx 在 cmets 单元格中被评论了多少次。到目前为止,我可以使每个单元格计数一次,但是一个包含BNxxxx的单元格中可能有多个cmet。

例如,这个:

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

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

这是我的代码:

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),'_') 没有任何结果,知道如何获得准确的喜欢

【问题讨论】:

  • 你用的是什么数据库?
  • yaya,但我想要的结果表明我猜想 BN 已经完全分解,而不仅仅是单元格中的第一次出现..
  • 我根据您对问题的修改更新了我的答案。

标签: sql oracle count cell sql-like


【解决方案1】:

你有问题。让我假设你有一个你关心的所有已知 BN 值的表。然后您可以执行以下操作:

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

这可能会很慢。

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

【讨论】:

  • 我认为这将是解决方案,只是得到一些 oracle 语法错误,我认为这与连接的执行方式或 concat 命令有关
  • 这是有效的,使用 , 而不是管道。使用 like 语句,我希望 cmets 在数字前有“BN”,因为 BN 表只有数字。我试过 ('BN',b.BRIDGE_NO, '%'),dosnt 似乎给出了预期的结果。任何想法
  • 使用 ('%BN' || bn.fullbn || '%')
  • 嘿 psarag12,谢谢,确实尝试过这个问题是 BN44 与 BN4455 相同
  • @cain2060,这就是为什么我建议使用正则表达式而不是简单的LIKE。不能使LIKE 变得贪婪,因此它不会选择匹配BN4455 而不是BN44
【解决方案2】:

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

您甚至可以在没有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 制作的 cmet。

如果您想在不聚合计数的情况下查看匹配的 cmets,请执行以下操作(基本上是取出外部查询):

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 之类的内容。

【讨论】:

  • 非常有趣!我从未见过connect by regex_substr 被这样使用。对于任何对此模式及其工作原理感兴趣的人,您可以在此处查看 alfasin 的答案stackoverflow.com/questions/19195280/…
  • 为什么需要AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL
  • 如果你省略它,你会得到一个笛卡尔连接。就个人而言,我真的不明白为什么,但它确实有效。
【解决方案3】:

尝试在您的选择语句中使用 distinct 关键字,为 cmets 提取唯一值。像这样:

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; 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-22
    • 1970-01-01
    • 1970-01-01
    • 2020-10-24
    • 1970-01-01
    • 2013-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多