Oracle SQL差异:COUNT(*)与实际结果集

时间:2016-06-01 19:46:17

标签: sql oracle count

我有一个应用程序可以跟踪文件被“尝试”从一个服务器移动到另一个服务器,以及何时“成功”或“失败”。&#34;尝试&#34;应该始终与成功&#34;成功配对。或者&#34;失败。&#34;然而,有63次“孤儿”尝试,这意味着有一些尝试没有报告成功或失败。我的第一个查询显示了我开始使用 63 数字的位置:我计算了所有次尝试并减去成功和< EM>故障 -

SELECT
(
    SELECT COUNT(*) FROM e_table
    WHERE e_comment LIKE '%attempt%'
    AND e_date >= '23-MAY-2016'
    AND e_date <= '26-MAY-2016'
)
-
(
    SELECT
    (
        SELECT COUNT(*) FROM e_table
        WHERE e_comment LIKE '%success%'
        AND e_date >= '23-MAY-2016'
        AND e_date <= '26-MAY-2016'
    )
    +
    (
        SELECT COUNT(*) FROM e_table
        WHERE e_comment LIKE '%failure%'
        AND e_date >= '23-MAY-2016'
        AND e_date <= '26-MAY-2016'
    ) FROM dual
) AS orphaned_attempts FROM dual;

因此,我在第63次尝试中获取特定 e_id 的第二个查询如下:

SELECT * FROM
(
    SELECT e_id FROM e_table
    WHERE e_comment LIKE '%attempt%'
    AND e_date >= '23-MAY-2016'
    AND e_date <= '26-MAY-2016'
)
MINUS
(
    SELECT e_id FROM e_table
    WHERE e_comment LIKE '%success%'
    AND e_date >= '23-MAY-2016'
    AND e_date <= '26-MAY-2016'
)
MINUS
(
    SELECT e_id FROM e_table
    WHERE e_comment LIKE '%failure%'
    AND e_date >= '23-MAY-2016'
    AND e_date <= '26-MAY-2016'
);

我需要(并期望基于第一个查询的结果集)是一个63行的结果集,其中一列包含孤立尝试的e_id。相反,我从第二个查询回来只有49行。非常感谢任何帮助。

7 个答案:

答案 0 :(得分:5)

SELECT
    a.e_id,
    coalesce(attempts, 0) attempts,
    coalesce(successes, 0) successes,
    coalesce(failures, 0) failures
FROM
    (
        SELECT e_id, count(*) as attempts FROM e_table
        WHERE e_comment LIKE '%attempt%' AND e_date BETWEEN '23-MAY-2016' AND '26-MAY-2016'
        GROUP BY e_id
    ) a
    full outer join
    (
        SELECT e_id, count(*) as successes FROM e_table
        WHERE e_comment LIKE '%success%' AND e_date BETWEEN '23-MAY-2016' AND '26-MAY-2016'
        GROUP BY e_id
    ) s
        on s.e_id = a.e_id
    full outer join
    (
        SELECT e_id, count(*) as failures FROM e_table
        WHERE e_comment LIKE '%failure%' AND e_date BETWEEN '23-MAY-2016' AND '26-MAY-2016'
        GROUP BY e_id
    ) f
        on f.e_id = coalesce(a.e_id, s.e_id)
WHERE
    coalesce(attempts, 0) <> coalesce(successes, 0) + coalesce(failures, 0)

我更改为完全外部联接,因此您可以在没有任何匹配尝试的情况下验证没有成功和/或失败。这可以让你找到e_id在日志记录中出错的地方。开始处理更精细的数字应该更容易,而不仅仅是id值列表。

其他人已经指出了对同一个id进行多次尝试的可能性,但是可以想象成功和失败都可以像在某种重试场景中那样记录吗?我们不知道完整的评论是什么样的。作为一种可能的解释,单个评论可以包含多个单词“尝试”,“成功”,“失败”吗?

以下是需要考虑的其他事项:您确定所有成功和失败事件都属于同一日期窗口吗?换句话说,尝试后会有一些延迟吗?如果这发生在午夜左右,它可能不会很长。您可能希望将成功和失败范围扩大到足以弥补这一点(并更改为左外连接。)

注意: where子句中的条件已被修改为允许多次尝试(如评论中所述),现在只是寻找尝试次数与成功次数之间的平衡和失败。

答案 1 :(得分:3)

您的计数不匹配可能源于每个e_id多次尝试。

示例:

Counting:       count (1,1,2,3) - ( count(2) + count(3) ) = 4 - (1 + 1) = 2

Set operations:       (1,1,2,3) - (      (2) +      (3) ) = (1)

要获得所需的ID,您只需按其分组并比较计数,例如:

select e_id 
from e_table
where e_date between date'2016-05-23' and date'2016-05-26'
group by e_id
having count(case when e_comment like '%attempt%' then 1 end) >
       count(case when e_comment like '%success%' or e_comment like '%failure%' then 1 end);

顺便说一下,不要在日期中使用字符串,而是使用正确的日期文字,如上所示。 (最重要的是:如果没有适当的to_date来指定匹配的nls_date_language,则永远不要使用月份名称。)

答案 2 :(得分:2)

您需要的查询类似于:

select e_id
from   e_table e1
where  e_comment like '%attempt%'
and    e_date between date '2016-05-23' and  date '2016-05-26'
and    not exists( select null
                   from   e_table e2
                   where  e2.e_id = e1.e_id
                   and    (e2.e_comment like '%success%' or 
                           e2.e_comment like '%failure%'))

这种语义似乎最符合您的要求。

我将日期条件从相关子查询中删除以允许 在指定窗口之外的成功和失败,但可能有助于添加表单的附加子句:

and e2.e_date >= date '2016-05-23

......或......

and e2.e_date >= e1.e_date

如果您在e_id上​​有索引并且基数接近唯一,那么性能将不依赖于此。

答案 3 :(得分:1)

更好地了解每个e_id的内容,然后决定要做什么;)

SELECT e_id,
       count(*) c,
       sum(sign(instr(e_comment, 'attempt'))) c_a, 
       sum(sign(instr(e_comment, 'success'))) c_s, 
       sum(sign(instr(e_comment, 'failure'))) c_f
 FROM e_table
 WHERE e_date >= '23-MAY-2016' AND e_date <= '26-MAY-2016'
GROUP BY e_id

答案 4 :(得分:1)

Oracle安装程序

CREATE TABLE e_comment ( ce_id, e_id, e_comment, e_date ) AS
SELECT '472', '125', 'is attempting to move',  TIMESTAMP '2016-05-23 09:49:10' FROM DUAL UNION ALL
SELECT '678', '125', 'is attempting to move',  TIMESTAMP '2016-05-23 11:37:09' FROM DUAL UNION ALL
SELECT '724', '125', 'has successfully moved', TIMESTAMP '2016-05-23 11:37:09' FROM DUAL UNION ALL
SELECT '983', '034', 'is attempting to move',  TIMESTAMP '2016-05-24 17:04:35' FROM DUAL UNION ALL
SELECT '643', '672', 'is attempting to move',  TIMESTAMP '2016-05-25 13:28:36' FROM DUAL UNION ALL
SELECT '026', '672', 'failed to move',         TIMESTAMP '2016-05-25 13:28:36' FROM DUAL UNION ALL
SELECT '087', '672', 'is attempting to move',  TIMESTAMP '2016-05-24 18:33:35' FROM DUAL UNION ALL
SELECT '921', '375', 'is attempting to move',  TIMESTAMP '2016-05-26 19:12:43' FROM DUAL UNION ALL
SELECT '345', '375', 'has successfully moved', TIMESTAMP '2016-05-26 19:12:43' FROM DUAL;

查询 - 获取尝试次数,成功次数和失败次数

一个更简单的查询,不需要多个自联接:

SELECT e_id,
       COUNT( CASE WHEN e_comment LIKE '%attempt%' THEN 1 END ) AS attempts,
       COUNT( CASE WHEN e_comment LIKE '%success%' THEN 1 END ) AS successes,
       COUNT( CASE WHEN e_comment LIKE '%failed%' THEN 1 END ) AS failures
FROM   e_comment
GROUP BY e_id;

<强>输出

E_ID   ATTEMPTS  SUCCESSES   FAILURES
---- ---------- ---------- ----------
034           1          0          0 
672           2          0          1 
375           1          1          0 
125           2          1          0 

查询 - 获取孤立的e_id s

SELECT e_id,
       COUNT( CASE WHEN e_comment LIKE '%attempt%' THEN 1 END ) AS attempts,
       COUNT( CASE WHEN e_comment LIKE '%success%' THEN 1 END ) AS successes,
       COUNT( CASE WHEN e_comment LIKE '%failed%' THEN 1 END ) AS failures
FROM   e_comment
GROUP BY e_id
HAVING COUNT( CASE WHEN e_comment LIKE '%attempt%' THEN 1 END )
       <> COUNT( CASE WHEN e_comment LIKE '%success%' THEN 1 END )
        + COUNT( CASE WHEN e_comment LIKE '%failed%' THEN 1 END );

<强>输出

E_ID   ATTEMPTS  SUCCESSES   FAILURES
---- ---------- ---------- ----------
034           1          0          0 
672           2          0          1 
125           2          1          0 

答案 5 :(得分:0)

您可以使用选择

中的位置获取所有行
   select * from e_table 
   where id in (SELECT * FROM
    (
        SELECT e_id FROM e_table
        WHERE e_comment LIKE '%attempt%'
        AND e_date >= '23-MAY-2016'
        AND e_date <= '26-MAY-2016'
    )
    MINUS
    (
        SELECT e_id FROM e_event
        WHERE e_comment LIKE '%success%'
        AND e_date >= '23-MAY-2016'
        AND e_date <= '26-MAY-2016'
    )
    MINUS
    (
        SELECT e_id FROM e_event
        WHERE e_comment LIKE '%failure%'
        AND e_date >= '23-MAY-2016'
        AND e_date <= '26-MAY-2016'
    ));

以这种方式获取所有涉及的行并轻松查找重复的id ..

   select id, count(*) from e_table 
   where id in (SELECT * FROM
    (
        SELECT e_id FROM e_table
        WHERE e_comment LIKE '%attempt%'
        AND e_date >= '23-MAY-2016'
        AND e_date <= '26-MAY-2016'
    )
    MINUS
    (
        SELECT e_id FROM e_event
        WHERE e_comment LIKE '%success%'
        AND e_date >= '23-MAY-2016'
        AND e_date <= '26-MAY-2016'
    )
    MINUS
    (
        SELECT e_id FROM e_event
        WHERE e_comment LIKE '%failure%'
        AND e_date >= '23-MAY-2016'
        AND e_date <= '26-MAY-2016'
    ));
    group by id
    having count(*) >1;

通过这种方式,您可以获得更多的条目

答案 6 :(得分:0)

以下内容应该有效。为了清楚起见,它使用了一个公用表表达式,但它不是必需的,可以使用常规LEFT OUTER JOIN编写。

WITH 
attempts AS (
    SELECT e_id
    FROM e_table
    WHERE e_comment LIKE '%attempt%'
),
results AS (
    SELECT e_id
    FROM e_table
    WHERE e_comment LIKE '%success%'
       OR e_comment LIKE '%failure%'
)
SELECT a.e_id
FROM attempts a
LEFT OUTER JOIN results r
  ON a.e_id = r.e_id
WHERE r.e_id IS NULL
  AND e_date >= '23-MAY-2016'
  AND e_date <= '26-MAY-2016';

它加入了成功/失败列表的尝试列表。如果尝试没有匹配的成功/失败并且它在期望的日期范围内,则返回相应的e_id