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

标签 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 作业用来聚合和填充另一个表。然而,这已经做了几天了。另一个表已完全填充并显示预期的记录数。我检查了 Oracle 作业日志,它显示所有成功,没有一个错误。

最佳答案

错误的结果可能是由损坏、错误和默默更改 SQL 语句的功能引起的。

  1. 索引损坏。索引损坏且索引中的数据与表中的数据不匹配的情况很少见。当查询计划更改并使用索引时,这会导致意外结果,但对于使用表访问的不同查询,一切看起来都很正常。有时只需重新构建对象即可解决此问题。如果没有,您将需要创建一个完全可重现的测试用例(包括数据);将它张贴在这里或将它提交给 Oracle 支持。追踪这件事可能需要很多小时。
  2. 错误。错误很少会导致查询在返回或更改数据时失败。同样,需要一个完全可重现的测试用例 对此进行诊断,这可能需要一段时间。
  3. 切换 SQL 的功能 有几种方法可以透明地更改 SQL 语句。查看虚拟专用数据库 (VPD)、DBMS_ADVANCED_REWRITE 和 SQL 转换框架。

为了排除 #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

这可以通过查看解释计划来检测。在下面的示例中,Predicate 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) 是一个旧的看起来像 cargo 崇拜编程的神话。)

关于Oracle Select * 返回行但 Select count(1) 返回 0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37888050/

相关文章:

oracle - 通过过滤多行选择查询

sql-server - 由于 SQL Server 没有包,程序员如何绕过它呢?

oracle - 获取 LONG RAW 的长度

sql - 这个 PL/SQL 触发器有什么问题?

sql - Oracle 窗口函数求和

sql - 在Oracle中执行ORDER BY后+0是什么意思

sql - Oracle 自定义排序

oracle - pl/sql 程序员在计算货币时常犯的错误是什么?

java - Google App Engine 无效公共(public) ID : -//Oracle Corporation//DTD Web Application 2. 3//EN