2011-06-08 87 views
4

我试图为Oracle 11g应用程序组织一个查询,并且遇到了问题。具有多个COUNT(DISTINCT xxx)的PL/SQL SELECT - 意外的结果

我就简化了真实的情景,使之更容易理解(也以保障客户的数据):

  • 表A是基表。它有一个已知的标识符,我将它传递给查询。
  • 对于表A中的每个条目,表B中可能有多个条目。表B包含我感兴趣的值。
  • 对于表B中的每个条目,表C中也可能有多个条目。表C包含我感兴趣的另一个值
  • 我也有一个XML片段,其中包含一个值列表,它可能与表C中的值相匹配,也可能不匹配。
  • 查询执行外连接XML,这样如果有匹配的值,它会再次返回值,否则它是空的。

我想要做的是取回我传入的标识符,B和C中唯一值的计数,以及XML部分中唯一值(和非空值)的计数的加入。

我当前的查询是:

SELECT 
    a.ID 
    , COUNT(DISTINCT b.VAL) AS B_VAL 
    , COUNT(DISTINCT c.VAL) AS C_VAL 
    , COUNT(DISTINCT xml.VAL) AS XML_VAL 
FROM a, b, c, 
    XMLTABLE('/field1/collection/value' passing my_xml_type 
    COLUMNS VAL VARCHAR2(50) PATH '.') xml 
WHERE 
     a.ID = b.SOME_ID 
    AND b.OTHER_ID = c.OTHER_ID 
    AND c.VAL = xml.VAL (+) 

现在,如果你忘了计数,只是返回行,一个例子结果集可能是这个样子:

ID  B_VAL  C_VAL  XML_VAL 
--------------------------------------- 
X  abc  123  123 
X  abc  456  null 
X  abc  789  789 
X  abc  789  789 

DESIRED:现在当我想做不同的计数时,我希望它能返回:

ID  B_VAL  C_VAL  XML_VAL 
--------------------------------------- 
X  1   3   2 

实际:但是,这是我收到的时候我把它们都为COUNT(DISTINCT ...):

ID  B_VAL  C_VAL  XML_VAL 
--------------------------------------- 
X  1   1   1 

替代方案: ...如果我走了DISTINCT随后的数,我得到:

ID  B_VAL  C_VAL  XML_VAL 
--------------------------------------- 
X  1   4   3 

怎么来的DISTINCT似乎只在特定的B_VAL操作,但服用它导致它在所有行工作,但没有采取独特性考虑?

是否有另一种方法来做到这一点,不需要将所有连接复制为子查询?我完全错过了这一点吗?

(请注意,我不是一个数据库开发人员,我刚刚被拉进来帮忙,所以很抱歉如果这是一个简单的问题...我已经搜索谷歌并浏览本网站的答案但发布之前)!

谢谢。


我发现,如果我把XML表格加入了那么计数明显作品OK跨越B_VAL和C_VAL ...所以也许这是一个很奇怪的甲骨文如何处理XML表连接?

+0

注意,我我发现如果我把XML表连接起来,那么在B_VAL和C_VAL之间的计数明显可以正常工作......对于Oracle如何处理XML表连接可能有些奇怪? – ChrisC 2011-06-08 06:37:37

+0

鉴于下面的答案,您使用的是哪个版本的Oracle?文森特给出的测试案例是否也失败了? – 2011-06-08 12:03:11

+0

@MikeyByCrikey,我现在在本地运行11.2.0.1,并且看到Vincent的不同结果。不幸的是,即使嵌套查询不适合我。此外,我需要找出目标生产数据库的版本,我不能只修补我的开发数据库... – ChrisC 2011-06-08 23:39:05

回答

4

由于Vincent的测试用例在10.2.0.3和11.2.0.2中可用,并且如果您使用的是早期版本的11g,这可能是bug 8816675:XMLexists查询返回带有选择DISTINCT的错误结果。该错误中的示例是指count(distinct)的问题。你没有明确地使用XMLexists,但是这个错误可能会对标题所暗示的影响有更大的影响,或者可能会在后台使用。

如果是这样的问题,你不能修补,你可能能够解决它通过包装非计数版本,仍然是不漂亮:

SELECT 
    A_ID 
    , COUNT(DISTINCT B_VAL) AS B_VAL 
    , COUNT(DISTINCT C_VAL) AS C_VAL 
    , COUNT(DISTINCT XML_VAL) AS XML_VAL 
FROM (
SELECT a.ID as A_ID, b.VAL as B_VAL, c.VAL as C_VAL, xml.VAL as XML_VAL 
FROM a, b, c 
    , XMLTABLE('/field1/collection/value' passing my_xml_type 
     COLUMNS VAL VARCHAR2(50) PATH '.') xml 
WHERE a.ID = b.SOME_ID 
AND b.OTHER_ID = c.OTHER_ID 
AND c.VAL = xml.VAL (+) 
) 
GROUP BY A_ID; 
+0

我认为你是对的,因为这是一个错误,因为11.2.0.1中的行为似乎有所不同(请参阅我对文森特的帖子的评论)。然而,有趣的是,即使当我作为子查询来做时,它也不起作用!我仍然得到X,1,1,1作为我的值而不是X,1,3,2 ...似乎还有一些与COUNT DISTINCT有关的其他错误,尽管这可能与此有关(8714580错误的结果来自DISTINCT查询与unnest的任何子查询,7661113查询重写不按预期与SELECT DISTINCT)。 – ChrisC 2011-06-08 23:37:40

+1

+1,nice catch :) @Chris:你可能想通过添加'rownum'伪列来实现子查询,这将迫使Oracle采取额外的步骤来运行子查询(而不是巧妙地将它与外部查询) – 2011-06-09 08:04:54

+0

@Vincent,我将ROWNUM添加到内部查询中,不幸的是仍然看到了相同的行为。我甚至证实ROWNUM正在通过再次测试并计算出rownums的数量。但是,如果我将连接取出到XML中,则COUNT DISTINCT会在B,C(和ROWNUM包含它)时返回正确的值,但这只会导致XML连接丢失。 @Alex,你可能是正确的XML存在错误! – ChrisC 2011-06-09 22:16:26

4

我无法用Oracle 10.2.0.3重现您的发现。

这里是我的设置:

SQL> CREATE TABLE a AS SELECT 'X' ID FROM dual; 

Table created 

SQL> CREATE TABLE b AS SELECT 'abc' val, 'X' some_id, 1 other_id FROM dual; 

Table created 

SQL> CREATE TABLE c AS 
    2  SELECT 1 other_id, '123' val, 
    3   XMLTYPE('<field1> 
    4      <collection><value>123</value></collection> 
    5      </field1>') my_xml_type 
    6  FROM dual UNION ALL 
    7  SELECT 1 other_id, '456' val, NULL FROM dual UNION ALL 
    8  SELECT 1 other_id, '789' val, 
    9   XMLTYPE('<field1> 
10      <collection><value>789</value></collection> 
11      <collection><value>789</value></collection> 
12      </field1>') my_xml_type 
13  FROM dual; 

Table created 

查询将返回正确的结果:

SQL> SELECT 
    2  a.ID 
    3 , COUNT(DISTINCT b.VAL) AS B_VAL 
    4 , COUNT(DISTINCT c.VAL) AS C_VAL 
    5 , COUNT(DISTINCT xml.VAL) AS XML_VAL 
    6 FROM a, b, c 
    7  , XMLTABLE('/field1/collection/value' passing my_xml_type 
    8     COLUMNS VAL VARCHAR2(50) PATH '.') xml 
    9 WHERE a.ID = b.SOME_ID 
10 AND b.OTHER_ID = c.OTHER_ID 
11 AND c.VAL = xml.VAL (+) 
12 GROUP BY a.id; 

ID  B_VAL  C_VAL XML_VAL 
-- ---------- ---------- ---------- 
X   1   3   2 

可以运行这个测试呢?

+0

通过此测试,我也在11.2.0.2(VirtualBox下的OTN开发人员日志VM)中获得了正确的结果。 – 2011-06-08 09:48:16

+0

当我在11.2.0.1下本地运行这个时,我没有得到这个结果......根据我原来的帖子得到X,1,1,1 ......看起来这是一个固定的bug ...我我需要检查我实际正在开发的远程数据库,因为我不知道它是哪个版本。 (可能更老......)我还需要找出最终的生产系统将与哪个版本对抗! – ChrisC 2011-06-08 23:13:42