【发布时间】:2023-03-28 10:16:01
【问题描述】:
我在让 SQL Server 为我们的 SQL 树查询返回与 Oracle 相同的结果时遇到了一点问题。
我们有一个带有属性的链接表
CHILD_ID, LINK_ID, PARENT_ID
还有一个带有ELEMENT_ID的元素表
在 Oracle 中我们使用这个
SELECT * FROM LINKS
JOIN ELEMENTS ON ELEMENT_ID = CHILD_ID
WHERE LINK_ID IN
(SELECT LINK_ID FROM LINKS CONNECT BY PRIOR CHILD_ID = PARENT_ID START WITH PARENT_ID = 'startid')
在 SQL Server 中我们使用这个
WITH TREE_LINKS AS
(SELECT CHILD_ID, LINK_ID FROM LINKS WHERE PARENT_ID = 'startid'
UNION ALL
SELECT CURRENT_LINKS.CHILD_ID, CURRENT_LINKS.LINK_ID
FROM LINKS CURRENT_LINKS
INNER JOIN TREE_LINKS t1 ON CURRENT_LINKS.PARENT_ID = t1.CHILD_ID)
SELECT * FROM TREE_LINKS
INNER JOIN LINKS ON TREE_LINKS.LINK_ID = LINKS.LINK_ID
INNER JOIN ELEMENTS ON ELEMENTS.ELEMENT_ID = TREE_LINKS.CHILD_ID
除了 1 个问题之外,这一切都很好。
在 Oracle 中,我们仅获取基于 LINK_ID 的每个唯一链接。在 SQL Server 中,我们获得了描述完整树的所有链接,当结构的不同分支中的多个其他元素下方存在一个元素时,该完整树可以包含重复项。
这意味着我们会从 SQL Server 获得大量重复行。我测试了添加
SELECT DISTINCT TREE_LINKS.LINK_ID AS TREE_LINK_ID, * from TREE_LINKS
在最后一个 select 语句中,但只要服务器有更多工作可以删除在不同分支中发现的重复项。
目前在 1 个测试用例中,Oracle 返回 20,000 行,SQL Server 返回 160 万行。到目前为止,我还没有找到让 SQL Server 快速返回相同结果的方法。
仅供参考:在递归中添加 DISTINCT 会导致
DISTINCT 运算符不允许出现在递归的递归部分 公用表表达式“TREE_LINKS”。
编辑:- 一个例子
如果我们有这样的链接
PARENT_ID, LINK_ID, CHILD_ID
1 1 2
2 2 3
3 3 4
1 4 3
有 4 个唯一元素,但完整树中有 6 个元素。这是因为元素 3 有 2 条路径
【问题讨论】:
-
您可能会从内部连接中获取 dup 子节点,请先尝试我在添加 distinct 之前给出的代码以先查看差异。另外,查找“内部联接”。如果两个孩子有相同的父母,那么您将获得同一父母与每个孩子的多条记录。
-
我不小心将 PARENT_ID 放在了其中一个语句中应该有 LINK_ID 的位置。以防万一你正在测试它。
-
你有没有 child_id == parent_id 的链接节点?因为我可以看到这为 sql-server 语法造成了问题,因为没有用于递归的停止语句。也许在“WHERE TREE_LINKS.CHILD_ID = NLINKS.PARENT_ID”之后添加这个“AND TREE_LINKS.LINK_ID NLINKS.LINK_ID”只是为了确保,因为在我看来,那部分不应该有重复。如果有,那也会在您拥有的连接中创建它们......我将把它添加到我的代码中以防万一。
-
CHILD_ID 永远不能匹配 PARENT_ID
-
嗯,当 startid 为 1 时,您有 from 1 >-2-3-4 >-3-4。好的,从此 sqlserver 的语法立即为您提供了两个父项(parent_id = 1 提供了 2 个元素),所以这可能就是为什么它给了您一些不同的东西……我稍后再看一遍。
标签: sql sql-server database oracle