具有多个 COUNT(DISTINCT xxx) 的 PL/SQL SELECT - 意外结果

发布于 2024-11-14 03:06:15 字数 1925 浏览 3 评论 0原文

我正在尝试对 Oracle 11g 应用程序进行查询,但遇到了问题。

我将简化实际场景,使其更易于理解(同时也保护客户端的数据):

  • 表 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

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

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

ACTUAL: 但是,当我将它们全部设置为 COUNT(DISTINCT ...):

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

ALTERNATIVE: ...并且如果然后我把 DISTINCT 从计数中去掉我得到:

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

为什么 DISTINCT 似乎只在特定的 B_VAL 内运行,但将其取出会导致它在所有行上运行但不考虑唯一性?

是否有另一种方法可以做到这一点,而不必将所有联接复制为子查询?我完全没有抓住要点吗?

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

谢谢。


我发现,如果我取出 XML 表连接,则不同的计数在 B_VAL 和 C_VAL 上工作正常...那么 Oracle 处理 XML 表连接的方式可能有点奇怪?

I'm trying to put together a query for an Oracle 11g application and I've run into a problem.

I'll simplify the real scenario to make it easier to understand (and also to protect the client's data):

  • Table A is the base table. It has a known identifier in it that I pass in to the query.
  • For each entry in Table A there may be multiple entries in Table B. Table B contains a value that I am interested in.
  • For each entry in Table B there may also be multiple entries in Table C. Table C contains another value I'm interested in.
  • I also have an XML snippet containing a list of values that may or may not match up to the values of interest in table C.
  • The query does an outer join to the XML so that if there is a matching value it will return the value again, otherwise it is null.

What I want to do is get back the identifier I passed in, a count of the unique values in B and C, as well as a count of the unique (and non-null) values from the XML part of the join.

My current query is:

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 (+)

Now if you forget about the counting and just return rows, an example result set might look something like this:

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

DESIRED: Now when I want to do the distinct counts, I'd like it to return:

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

ACTUAL: However, this is what I'm getting when I have them all as COUNT(DISTINCT ...):

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

ALTERNATIVE: ...and if I take the DISTINCT out of the counts then I get:

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

How come the DISTINCT seems to be operating only within a particular B_VAL, but taking it out causes it to operate across all the rows but not taking uniqueness into account?

Is there another way of doing this that doesn't involve having to replicate all the joins as a sub-query? Have I missed the point entirely?

(Please note, I'm not a DB developer at all, I've just been pulled in to help out, so sorry if this is an easy problem... I HAVE searched Google and browsed this site for answers before posting, though!)

Thanks.


I've found that if I take the XML table join out then the count distinct works OK across the B_VAL and C_VAL... So perhaps it's something weird with how Oracle handles XML table joins?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

缱绻入梦 2024-11-21 03:06:15

由于 Vincent 的测试用例适用于 10.2.0.3 和 11.2.0.2,并且如果您使用的是 11g 的早期版本,则这可能是错误 8816675:XMLexists 查询使用 select DISTINCT 返回错误结果。 bug 中的示例涉及 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;

As Vincent's test case works in 10.2.0.3 and 11.2.0.2, and if you're at an earlier version of 11g, this could be bug 8816675: XMLexists query returns wrong results with a select DISTINCT. The example in the bug is referring to a problem with count(distinct). You aren't explicitly using XMLexists, but the bug may have a wider impact then the title suggests, or it may be used under the hood.

If this is the problem, and you can't patch up, you might be able to work around it by wrapping the non-count version, which still isn't pretty:

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;
苦笑流年记忆 2024-11-21 03:06:15

我无法使用 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

你能运行这个测试用例吗?

I can't reproduce your finding with Oracle 10.2.0.3.

Here's my setup:

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

the query returns the right result:

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

Can you run this test case?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文