【问题标题】:Distinct causes queries to no longer work as expected. How do I fix this issue?Distinct 导致查询不再按预期工作。我该如何解决这个问题?
【发布时间】:2018-08-28 07:58:18
【问题描述】:

我有一个节点分层表,其中包含两个表“属性”和“值”,由耦合表链接。现在我正在尝试进行查询以返回一个特定的树,其中每个节点的属性和子节点的值无论级别如何。

由于我没有找到在一个查询中执行此操作的方法,因此我将其拆分为 2 个,分别获取孩子并递归地使用存储过程。下面的查询是为特定父节点收集子节点及其所有信息的查询。

但是我遇到了一些奇怪的行为:

我首先获取节点并使用子查询来获取属性。这些查询单独工作正常,但是一旦我将它们组合起来,它们就会忽略过滤,并在我尝试使用 DISTINCT 消除重复项时立即打印所有属性。

select xmlelement("tns:nodes",
    xmlattributes('http://somenamespace.com/' as "xmlns:tns"),
    xmlagg(xmlelement("tns:node",
        xmlelement("tns:code", n.code),
        (select xmlelement("tns:attributes",
                xmlagg(xmlelement("tns:attribute",
                    xmlelement("tns:name", t.name)
                ))
            )
            from (select DISTINCT att_a.name
                    from attributes2 att_a
                    inner join attrib_value_node2 att_avnu on att_avnu.attribute_id = att_a.id
                    where att_avnu.node_id in (select id from nodes2 start with code = n.code connect by prior ID = PARENTID)
                 ) t
        )
    )
))
FROM   NODES2 n
where n.parentID in (select id from nodes2 where code = 'TESTS')
and n.id in (select parentID from nodes2)
order by n.code asc;

当我删除 DISTINCT 时,查询按预期工作。但是它有重复,因为有些节点具有相同的属性但值不同。我试图通过只选择 DISTINCT 属性来过滤这些,但是由于某种原因,一旦我把它放在那里,整个过滤就会停止工作,它只会打印所有属性。

当我通过手动将 n.code 替换为字符串来单独运行属性查询时,它再次正常工作。为什么当查询作为一个整体运行时,DISTINCT 会导致问题?另外我该如何解决这个问题?我知道 DISTINCT 和 collect by 对彼此不太友好,但我没有在同一个查询中使用它们。

数据库脚本和数据:

DROP TABLE NODES2;
DROP TABLE VALUES2;
DROP TABLE ATTRIBUTES2;
DROP TABLE ATTRIB_VALUE_NODE2;

CREATE TABLE NODES2 
(   
    "ID" NUMBER, 
    "PARENTID" NUMBER,
    "CODE" VARCHAR2(20)
);

CREATE UNIQUE INDEX "NODES2_PK" ON "NODES2" ("ID");

CREATE TABLE VALUES2 
(   
    "ID" NUMBER,
    "NAME" VARCHAR2(200)
);

CREATE UNIQUE INDEX "VALUES2_PK" ON "VALUES2" ("ID");

CREATE TABLE ATTRIBUTES2 
(   
    "ID" NUMBER,
    "NAME" VARCHAR2(200)
);

CREATE UNIQUE INDEX "ATTRIBUTES2_PK" ON "ATTRIBUTES2" ("ID");

CREATE TABLE "ATTRIB_VALUE_NODE2" 
(
    "ATTRIBUTE_ID" NUMBER NOT NULL, 
    "ATTRIB_VALUE_ID" NUMBER NOT NULL, 
    "NODE_ID" NUMBER NOT NULL
);

INSERT INTO "NODES2" (ID, CODE) VALUES (1,'TESTS');
INSERT INTO "NODES2" (ID, PARENTID, CODE) VALUES (2,1,'TST1');
INSERT INTO "NODES2" (ID, PARENTID, CODE) VALUES (3,1,'TST2');
INSERT INTO "NODES2" (ID, PARENTID, CODE) VALUES (4,1,'TST3');
INSERT INTO "NODES2" (ID, PARENTID, CODE) VALUES (5,2,'TST1-1');
INSERT INTO "NODES2" (ID, PARENTID, CODE) VALUES (6,2,'TST1-2');
INSERT INTO "NODES2" (ID, PARENTID, CODE) VALUES (7,3,'TST2-1');
INSERT INTO "NODES2" (ID, PARENTID, CODE) VALUES (8,3,'TST2-2');
INSERT INTO "NODES2" (ID, PARENTID, CODE) VALUES (9,3,'TST2-3');
INSERT INTO "NODES2" (ID, PARENTID, CODE) VALUES (10,4,'TST3-1');
INSERT INTO "NODES2" (ID, PARENTID, CODE) VALUES (11,4,'TST3-2');

Insert into ATTRIBUTES2 (ID,NAME) values (1,'TestAttribute');
Insert into ATTRIBUTES2 (ID,NAME) values (2,'TestAttribute2');
Insert into ATTRIBUTES2 (ID,NAME) values (3,'TestAttribute3');
Insert into ATTRIBUTES2 (ID,NAME) values (4,'TestAttribute4');
Insert into ATTRIBUTES2 (ID,NAME) values (5,'TestAttribute5');

Insert into "VALUES2" (ID,NAME) values (1,'TestValue1');
Insert into "VALUES2" (ID,NAME) values (2,'TestValue2');
Insert into "VALUES2" (ID,NAME) values (3,'TestValue3');
Insert into "VALUES2" (ID,NAME) values (4,'TestValue4');
Insert into "VALUES2" (ID,NAME) values (5,'TestValue5');

Insert into ATTRIB_VALUE_NODE2 (ATTRIBUTE_ID,ATTRIB_VALUE_ID,NODE_ID) values (1,1,5);
Insert into ATTRIB_VALUE_NODE2 (ATTRIBUTE_ID,ATTRIB_VALUE_ID,NODE_ID) values (2,2,5);
Insert into ATTRIB_VALUE_NODE2 (ATTRIBUTE_ID,ATTRIB_VALUE_ID,NODE_ID) values (1,2,6);
Insert into ATTRIB_VALUE_NODE2 (ATTRIBUTE_ID,ATTRIB_VALUE_ID,NODE_ID) values (1,3,7);
Insert into ATTRIB_VALUE_NODE2 (ATTRIBUTE_ID,ATTRIB_VALUE_ID,NODE_ID) values (3,3,8);
Insert into ATTRIB_VALUE_NODE2 (ATTRIBUTE_ID,ATTRIB_VALUE_ID,NODE_ID) values (3,4,8);

没有 DISTINCT 的输出:

<tns:nodes xmlns:tns="http://somenamespace.com/">
    <tns:node>
        <tns:code>TST1</tns:code>
        <tns:attributes>
            <tns:attribute>
                <tns:name>TestAttribute</tns:name>
            </tns:attribute>
            <tns:attribute>
                <tns:name>TestAttribute2</tns:name>
            </tns:attribute>
            <tns:attribute>
                <tns:name>TestAttribute</tns:name>
            </tns:attribute>
        </tns:attributes>
    </tns:node>
    <tns:node>
        <tns:code>TST2</tns:code>
        <tns:attributes>
            <tns:attribute>
                <tns:name>TestAttribute</tns:name>
            </tns:attribute>
            <tns:attribute>
                <tns:name>TestAttribute3</tns:name>
            </tns:attribute>
            <tns:attribute>
                <tns:name>TestAttribute3</tns:name>
            </tns:attribute>
        </tns:attributes>
    </tns:node>
    <tns:node>
        <tns:code>TST3</tns:code>
        <tns:attributes/>
    </tns:node>
</tns:nodes>

DISTINCT 的输出:

<tns:nodes xmlns:tns="http://somenamespace.com/">
    <tns:node>
        <tns:code>TST1</tns:code>
        <tns:attributes>
            <tns:attribute>
                <tns:name>TestAttribute</tns:name>
            </tns:attribute>
            <tns:attribute>
                <tns:name>TestAttribute2</tns:name>
            </tns:attribute>
            <tns:attribute>
                <tns:name>TestAttribute3</tns:name>
            </tns:attribute>
        </tns:attributes>
    </tns:node>
    <tns:node>
        <tns:code>TST2</tns:code>
        <tns:attributes>
            <tns:attribute>
                <tns:name>TestAttribute</tns:name>
            </tns:attribute>
            <tns:attribute>
                <tns:name>TestAttribute2</tns:name>
            </tns:attribute>
            <tns:attribute>
                <tns:name>TestAttribute3</tns:name>
            </tns:attribute>
        </tns:attributes>
    </tns:node>
    <tns:node>
        <tns:code>TST3</tns:code>
        <tns:attributes>
            <tns:attribute>
                <tns:name>TestAttribute</tns:name>
            </tns:attribute>
            <tns:attribute>
                <tns:name>TestAttribute2</tns:name>
            </tns:attribute>
            <tns:attribute>
                <tns:name>TestAttribute3</tns:name>
            </tns:attribute>
        </tns:attributes>
    </tns:node>
</tns:nodes>

预期输出:

<tns:nodes xmlns:tns="http://somenamespace.com/">
    <tns:node>
        <tns:code>TST1</tns:code>
        <tns:attributes>
            <tns:attribute>
                <tns:name>TestAttribute</tns:name>
            </tns:attribute>
            <tns:attribute>
                <tns:name>TestAttribute2</tns:name>
            </tns:attribute>
        </tns:attributes>
    </tns:node>
    <tns:node>
        <tns:code>TST2</tns:code>
        <tns:attributes>
            <tns:attribute>
                <tns:name>TestAttribute</tns:name>
            </tns:attribute>
            <tns:attribute>
                <tns:name>TestAttribute3</tns:name>
            </tns:attribute>
        </tns:attributes>
    </tns:node>
    <tns:node>
        <tns:code>TST3</tns:code>
    </tns:node>
</tns:nodes>

【问题讨论】:

  • 包含一些示例数据、您当前获得的结果(有和没有不同)以及您实际想要的数据结果会很有帮助。全部作为格式化文本而不是图像。
  • @AlexPoole ,我已经添加了输出。正如您所看到的,由于某种原因,输出 WITH distinct 会阻止过滤工作。
  • 这些输出的原始数据是什么?
  • @AlexPoole 我添加了一个 SQL 脚本供您测试。包括表格和数据。我没有添加钥匙或任何东西。只是数据。我还更新了结果和查询以适应表格。我希望你能告诉我为什么会这样和/或我可以如何做到这一点?

标签: sql oracle oracle12c hierarchical-data sqlxml


【解决方案1】:

您的两个查询的执行计划很有趣。我无法立即看到它为什么会丢失过滤步骤或相关性。您可能需要提出 SR 以获得完整的解释。

您可以在单个查询中完成此操作,将单个连接方式加入到耦合和属性表中:

select xmlserialize(document
  xmlelement("tns:nodes",
    xmlattributes('https//somenamespace.com/' as "xmlns:tns"),
    xmlagg(
      xmlelement("tns:node",
        xmlelement("tns:code", t.code),
        xmlelement("tns:attributes",
          xmlagg(
            xmlelement("tns:attribute",
              xmlelement("tns:name", t.name)
            )
            order by t.name
          )
        )
      )
      order by t.code
    )
  )
  indent size = 2
)
from (
  select distinct n.code, a.name
  from (
    select id, prior code as code
    from nodes2
    where id != connect_by_root (id)
    start with code = 'TESTS'
    connect by prior id = parentid
  ) n
  join attrib_value_node2 avn on avn.node_id = n.id
  join attributes2 a on a.id = avn.attribute_id
) t
group by t.code;

您的样本数据会产生:

<tns:nodes xmlns:tns="https//somenamespace.com/">
  <tns:node xmlns:tns="https//somenamespace.com/">
    <tns:code xmlns:tns="https//somenamespace.com/">TST1</tns:code>
    <tns:attributes xmlns:tns="https//somenamespace.com/">
      <tns:attribute xmlns:tns="https//somenamespace.com/">
        <tns:name xmlns:tns="https//somenamespace.com/">TestAttribute</tns:name>
      </tns:attribute>
      <tns:attribute xmlns:tns="https//somenamespace.com/">
        <tns:name xmlns:tns="https//somenamespace.com/">TestAttribute2</tns:name>
      </tns:attribute>
    </tns:attributes>
  </tns:node>
  <tns:node xmlns:tns="https//somenamespace.com/">
    <tns:code xmlns:tns="https//somenamespace.com/">TST2</tns:code>
    <tns:attributes xmlns:tns="https//somenamespace.com/">
      <tns:attribute xmlns:tns="https//somenamespace.com/">
        <tns:name xmlns:tns="https//somenamespace.com/">TestAttribute</tns:name>
      </tns:attribute>
      <tns:attribute xmlns:tns="https//somenamespace.com/">
        <tns:name xmlns:tns="https//somenamespace.com/">TestAttribute3</tns:name>
      </tns:attribute>
    </tns:attributes>
  </tns:node>
</tns:nodes>

XMLSerialize 调用只是为了很好地格式化文档。

命名空间声明是重复的,这似乎是嵌套 XMLAgg 调用和关联的 group-by 子句的产物;不幸的是,我看不到不生产这些的方法,但我认为从技术上讲它们并不重要。

【讨论】:

  • 嘿@AlexPoole,感谢您的帮助。我已经分析了查询,而输出确实返回了我期望的响应。它背后的逻辑似乎并不完全符合我的要求。我应该指定得更好。如果我理解正确,查询会返回其直接子代的属性。但是可以有更多级别。在这种情况下,我需要任何孩子使用的属性列表,无论他们处于什么级别。因此,在树的最高级别上,您将拥有所有属性,并且随着您在树中越低,您获得的属性就越少。关于如何做到这一点的任何想法?
猜你喜欢
  • 2022-10-17
  • 2015-02-13
  • 2020-03-25
  • 2020-02-14
  • 2019-03-14
  • 1970-01-01
相关资源
最近更新 更多