Distinct 导致查询不再按预期工作。我该如何解决这个问题?
Distinct causes queries to no longer work as expected. How do I fix this issue?
我有一个分层的 table 节点,其中 2 tables 'Attributes' 和 'Values' 通过耦合 table 链接。现在我正在尝试查询 return 一棵特定的树,其中每个节点的属性和其子节点的值,无论级别如何。
由于我没有找到在一个查询中执行此操作的方法,因此我将其拆分为 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>
你的两个查询的执行计划很有趣。我不能立即明白为什么它会丢失过滤步骤或相关性。您可能需要提出 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 调用和关联的分组依据子句的产物;不幸的是,我找不到不产生这些的方法,但我想从技术上讲它们并不重要。
我有一个分层的 table 节点,其中 2 tables 'Attributes' 和 'Values' 通过耦合 table 链接。现在我正在尝试查询 return 一棵特定的树,其中每个节点的属性和其子节点的值,无论级别如何。
由于我没有找到在一个查询中执行此操作的方法,因此我将其拆分为 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>
你的两个查询的执行计划很有趣。我不能立即明白为什么它会丢失过滤步骤或相关性。您可能需要提出 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 调用和关联的分组依据子句的产物;不幸的是,我找不到不产生这些的方法,但我想从技术上讲它们并不重要。