Oracle+SQL Server树查询问题

Oracle+SQL Server树查询问题,sql,sql-server,database,oracle,Sql,Sql Server,Database,Oracle,对于SQL树查询,让SQL Server返回与Oracle相同的结果有点问题 我们有一个带有属性的链接表 CHILD_ID, LINK_ID, PARENT_ID 以及元素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_

对于SQL树查询,让SQL Server返回与Oracle相同的结果有点问题

我们有一个带有属性的链接表

CHILD_ID, LINK_ID, PARENT_ID
以及元素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')
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
在SQL Server中,我们使用

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')
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中,我们仅获得基于链接ID的每个唯一链接。在SQL Server中,我们获得描述完整树的所有链接,当结构的不同分支中的多个其他元素下方存在一个元素时,该树可能包含重复的链接

这意味着我们从SQLServer获得大量重复的行。我测试了添加

SELECT DISTINCT TREE_LINKS.LINK_ID AS TREE_LINK_ID, * from TREE_LINKS 
在上一个select语句中,但只要服务器有更多的工作,就可以删除不同分支中的重复项

在目前的1个测试用例中,Oracle返回20000行,SQL Server返回160万行。到目前为止,我还没有找到让SQLServer像fast一样返回相同结果的方法

仅供参考:在递归原因中添加DISTINCT

递归函数的递归部分不允许使用DISTINCT运算符 通用表表达式“树链接”

编辑:-一个例子

如果我们有这样的链接

PARENT_ID, LINK_ID, CHILD_ID
1          1        2
2          2        3 
3          3        4
1          4        3
有4个独特的元素,但在完整的树中有6个元素。这是因为元素3有两条路径

SELECT LINK_ID
  FROM LINKS
  START WITH PARENT_ID = 'startid'
  CONNECT BY PRIOR CHILD_ID = PARENT_ID
应该相当于

在下面和第一次编辑中编辑:在第二次选择中将父\u ID更改为链接\u ID

WITH TREE_LINKS(CHILD_ID, LINK_ID) AS 
   (SELECT CHILD_ID, LINK_ID
    FROM LINKS
    WHERE PARENT_ID = 'startid'
        UNION ALL
    SELECT NLINKS.CHILD_ID, NLINKS.LINK_ID
    FROM LINKS as NLINKS, TREE_LINKS
    WHERE TREE_LINKS.CHILD_ID = NLINKS.PARENT_ID)

SELECT LINK_ID FROM TREE_LINKS

其余的应该与我所知道的相似

编辑:可能类似于:

WITH TREE_LINKS(CHILD_ID, LINK_ID) AS 
   (SELECT CHILD_ID, LINK_ID
    FROM LINKS
    WHERE PARENT_ID = 'startid'
        UNION ALL
    SELECT NLINKS.CHILD_ID, NLINKS.LINK_ID
    FROM LINKS as NLINKS, TREE_LINKS
    WHERE TREE_LINKS.CHILD_ID = NLINKS.PARENT_ID)

SELECT * FROM LINKS as TLINKS
JOIN ELEMENTS ON ELEMENT_ID = TLINKS.CHILD_ID
WHERE TLINKS.LINK_ID IN
(SELECT TREE_LINKS.LINK_ID FROM TREE_LINKS)
但我目前没有mssql或oracle来测试它


编辑:从查询中删除并删除树链接.LINK\u ID NLINKS.LINK\u ID,因为不需要它。

这会在两种情况下返回重复项。也就是说,如果狭窄的不同分支中的两个元素具有相同的子元素,并且该子元素具有多个子元素,则可以多次获得这些子元素链接。也许在这个查询上执行DISTINCT会比我现在拥有的更快。您的SQL语句似乎工作得很好。它在大约1分钟内得到20000个结果。比获得全部160万然后使用distinct进行过滤快5倍。我需要再做一点测试。好的。最后一个查询速度很快,事实上,不需要和树链接.LINKS\u ID NLINKS.LINK\u ID,这会使它稍微慢一点。这个SQL实际上和我的一样,我不明白为什么你的SQL要快得多,返回的是21000个而不是160万个条目,然后我就明白了。在SQL中,最后一个In子句的副作用是非常有效地过滤重复项。树链接仍然返回160万行,但IN子句仅在58秒内将结果过滤到21000行。我刚刚向查询计划器确认树链接仍然包含160万行,现在是1分钟的98%。您可能从InnerJoin中获得dup子级,在添加distinct之前,请尝试我给出的代码,以首先查看差异。另外,查找内部连接。如果两个子项具有相同的父项,则每个子项都将获得相同父项的多条记录。我无意中在其中一条语句中应该有链接ID的位置放置了父项ID。以防万一,您正在测试它。您是否有任何链接节点具有child\u id==parent\u id?因为我可以认为这是sql server语法的一个问题,因为递归没有停止语句。也许在TREE\u LINKS.CHILD\u ID=NLINKS.PARENT\u ID之后添加这个和TREE\u LINKS.LINK\u ID NLINKS.LINK\u ID只是为了确保,因为在我看来,那个部分不应该有重复的。如果有的话,也会在连接中创建它们。。。我将把它添加到我的代码中以防万一。CHILD\u ID永远无法匹配PARENT\u ID嗯,当1是startid时,您有1>-2-3-4>-3-4。好的,从这一点来看,sqlserver的语法立即为您提供了两个父元素,parent_id=1为您提供了两个元素,这可能就是它为您提供不同内容的原因。。。我过一会儿再看一遍。