Oracle Select *返回行但Select count(1)返回0

时间:2016-06-17 18:25:31

标签: oracle

所以,这很奇怪,这是我以前从未见过的。我希望有人有一个神奇的答案可以解释这个问题......

SELECT * FROM TABLE -- returns rows... a lot of rows

然而,

SELECT COUNT(1) FROM TABLE -- returns zero (0), as in the number zero (0) as the result

这是表结构:

CREATE TABLE TRACKING (
  A_ID NUMBER,
  D_CODE NUMBER,
  HOD NUMBER,
  ADR_CNT NUMBER,
  TTL_CNT NUMBER,
  CREATED DATE,
  MODIFIED DATE
);
CREATE INDEX HOD_D_CODE_IDX ON TRACKING (HOD, D_CODE);
CREATE UNIQUE INDEX TRACKING_PK ON TRACKING (A_ID, D_CODE, HOD);
CREATE INDEX MOD_DATE_IDX ON TRACKING (MODIFIED);
ALTER TABLE TRACKING ADD CONSTRAINT TRACKING_PK PRIMARY KEY (A_ID, D_CODE, HOD);

Oracle表如何有行但count(1)返回零?我在网上做了一些搜索,但一无所获。我发现的唯一其他帖子与MS SQL Server有关。这种情况发生在Oracle。

有什么想法吗?任何人吗?

提前感谢您提供的任何帮助。

我可能会添加另一件事,希望它能帮助回答这个难题,这个表被Oracle Job用来聚合和填充另一个表。但是,现在已经完成了几天。另一个表已完全填充并显示预期记录计数。我检查了Oracle作业日志,它显示了所有成功,而不是一个错误。

2 个答案:

答案 0 :(得分:1)

错误的结果可能是由于静默更改SQL语句的损坏,错误和功能造成的。

  1. 损坏索引。索引很少被破坏,索引中的数据与表中的数据不匹配。当查询计划更改并使用索引时,这会导致意外结果,但对于使用表访问的不同查询,一切看起来都很正常。有时只需重新构建对象就可以解决这个问题。如果没有,您需要创建一个完全可重现的测试用例(包括数据);要么在此发布,要么将其提交给Oracle支持。可能需要很长时间才能跟踪此情况。
  2. 错误。在返回或更改数据时,很少有错误会导致查询失败。同样,需要完全可重现的测试用例 诊断这个,可能需要一段时间。
  3. 切换SQL的功能有几种方法可以透明地更改SQL语句。查看虚拟专用数据库(VPD),DBMS_ADVANCED_REWRITE和SQL转换框架。
  4. 为了排除#3,下面的代码向您展示了执行此操作的邪恶方法之一,以及如何检测它。首先,创建架构和一些数据:

    CREATE TABLE TRACKING (
      A_ID NUMBER,
      D_CODE NUMBER,
      HOD NUMBER,
      ADR_CNT NUMBER,
      TTL_CNT NUMBER,
      CREATED DATE,
      MODIFIED DATE
    );
    CREATE INDEX HOD_D_CODE_IDX ON TRACKING (HOD, D_CODE);
    CREATE UNIQUE INDEX TRACKING_PK ON TRACKING (A_ID, D_CODE, HOD);
    CREATE INDEX MOD_DATE_IDX ON TRACKING (MODIFIED);
    ALTER TABLE TRACKING ADD CONSTRAINT TRACKING_PK PRIMARY KEY (A_ID, D_CODE, HOD);
    
    insert into tracking values (1,2,3,4,5,sysdate,sysdate);
    commit;
    

    首先,一切都按预期工作:

    SQL> SELECT * FROM TRACKING;
    
          A_ID     D_CODE        HOD    ADR_CNT    TTL_CNT CREATED   MODIFIED
    ---------- ---------- ---------- ---------- ---------- --------- ---------
             1          2          3          4          5 17-JUN-16 17-JUN-16
    
    SQL> SELECT COUNT(1) FROM TRACKING;
    
      COUNT(1)
    ----------
             1
    

    然后有人这样做:

    begin
      sys.dbms_advanced_rewrite.declare_rewrite_equivalence(
        'april_fools',
        'SELECT COUNT(1) FROM TRACKING',
        'SELECT 0 FROM TRACKING WHERE ROWNUM = 1',
        false);
    end;
    /
    

    现在结果是"错误":

    SQL> ALTER SESSION SET query_rewrite_integrity = trusted;
    
    Session altered.
    
    SQL> SELECT COUNT(1) FROM TRACKING;
    
      COUNT(1)
    ----------
             0
    

    这可以通过查看解释计划来检测。在下面的示例中,谓词2 - filter(ROWNUM=1)是一个错误的线索,因为该谓词不在原始查询中。有时"注意"解释计划的一部分将告诉你为什么它被转换,但有时它只提供线索。

    SQL> explain plan for SELECT COUNT(1) FROM TRACKING;
    
    Explained.
    
    SQL> select * from table(dbms_xplan.display);
    
    PLAN_TABLE_OUTPUT
    ------------------------------------------------------------------------------------------
    Plan hash value: 1761840423
    
    ------------------------------------------------------------------------------------
    | Id  | Operation         | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
    ------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |                |     1 |     2 |     1   (0)| 00:00:01 |
    |   1 |  VIEW             |                |     1 |     2 |     1   (0)| 00:00:01 |
    |*  2 |   COUNT STOPKEY   |                |       |       |            |          |
    |   3 |    INDEX FULL SCAN| HOD_D_CODE_IDX |     1 |       |     1   (0)| 00:00:01 |
    ------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - filter(ROWNUM=1)
    
    15 rows selected.
    

    (在不相关的注释上 - 始终使用COUNT(*)代替COUNT(1)COUNT(1)是一个古老的神话,看起来像货物崇拜节目。)

答案 1 :(得分:-1)

COUNT(SomeColumn)将仅返回包含SomeColumn的非空值的行数。 COUNT(*)和COUNT(' Foo')将返回表格中的总行数。

来源:Count(*) vs Count(1)

您的列1是否可能对所有寄存器都为NULL?如果它根本没有NULL,它应该作为Count(*)返回该表中的所有行,如果是这种情况,我们需要更多信息来帮助你。