【问题标题】:MS SQL Server - How to create a view using hierarchical queryMS SQL Server - 如何使用分层查询创建视图
【发布时间】:2021-08-07 16:36:46
【问题描述】:

我想使用 with 和删除 4 连接创建分层查询,有人可以帮助我是 SQL 视图的初学者。

CREATE VIEW CAR( ID, CARLEVEL) AS    
select
t.C_ID,
coalesce(d.C_ID, coalesce(c.C_ID, coalesce(b.C_ID, 
coalesce(a.C_ID, t.C_ID))))
from tablex t LEFT OUTER JOIN tablex a LEFT OUTER JOIN tablex b 
LEFT OUTER JOIN tablex c 
LEFT OUTER JOIN tablex d ON c.Title = d.C_ID ON b.Title = c.C_ID 
ON a.Title = b.C_ID ON t.Title = a.C_ID

Tablex 的内容是:

 C_ID    Title         
 67       Null
 68       Null
 69       68
 70       68
 71       68
 72       Null
 81       Null
 82       81
 83       81
 84       Null
 86       Null
 87       Null
104       81
105       81
106       81
107       Null
4707      81

我对 CTE 的期望是:

ID    CAR LEVEL
69     68
70     68
71     68
68     68
82     81
83     81
104    81
105    81
106    81
4707  81
81     81

【问题讨论】:

  • 没有分层引擎。递归查询的运行速度不会比 JOIN 快。如果您使用hierarchyid 而不是自引用 ID/Parent_ID,您将获得更好的性能。 将消除所有连接并将子搜索转换为简单的范围搜索
  • hierarchyid 值相当于节点 ID 的二进制路径,例如 1/3/8/678。当您搜索1/3 的子代时,服务器将一次性搜索所有以1/3 开头的hierarchyid 值。
  • 我认为您正在寻找的是所谓的递归公用表表达式。一个很好的例子可以在这里找到:sqlservertutorial.net/sql-server-basics/…
  • 为什么要嵌套COALESCE 函数? COALESCE,不像 ISNULL 允许 2+ 参数。
  • @satcha 为此,您需要递归 CTE。同样,您不会从中获得任何性能。充其量它会和 JOIN 一样快。仅当您想要处理超过 4 个级别时才需要递归 CTE。 COALESCE 没那么贵。 This article shows how to use recursive CTEs 用于分层查询

标签: sql sql-server common-table-expression create-view hierarchical-query


【解决方案1】:

没有hierarchical engine。有层次类型hierarchyid 可以表示层次结构并大大提高性能很多,但从 cmets 看来你不想使用它。

要像这样查询自引用层次结构,您可以像您所做的那样将表连接到特定级别,或者使用递归Common Table Expression。 CTE 有点像在查询本身中定义“视图”。一个重要的区别是 CTE 可以引用自身,从而创建递归 CTE。

This article 以分层查询为例说明了如何使用 CTE。

CTE 的一部分选择“根”行。这被称为anchor,因为这是我们开始的地方。 第二个,递归查询,选择与“先前”(锚点)结果相关的那些

在您的情况下,查询看起来像:

With MyCTE
AS (
    --Anchor. Get the roots
    SELECT
        t.ID,
        NULL as ParentID
    FROM tablex 
    WHERE ParentID is null
    UNION ALL
    --Recursive. Get the direct descendants of the "previous" case
    SELECT 
        t.ID,
        t.ParentID
    FROM tablex t 
        INNER JOIN MyCTE m on m.ID=t.ParentID
    WHERE t.ParentID is NOT NULL
)
SELECT t.ID as CarID, t.ParentID
FROM MyCTE

要获得级别,我们可以添加以 0 或 1 开头的另一列,并在递归查询中递增:

With MyCTE
AS (
    -- Anchor
    SELECT
        ID,
        ParentID,
        1 as Level.           -- Start with Level = 1
    FROM tablex 
    WHERE ParentID is null
    UNION ALL
    -- Recursive
    SELECT 
        t.ID,
        t.ParentID,
        m.Level+1 as Level.   -- Increment the level
    FROM tablex t 
        INNER JOIN MyCTE m on m.ID=t.ParentID
    WHERE t.ParentID is NOT NULL
)
SELECT 
    ID as CarID, 
    Level as CarLevel
FROM MyCTE

【讨论】:

  • 非常感谢,我使用了这种方法,我的意思是 CTE,但我没有得到与 4JOINS 相同的结果(缺少一些记录)。在这种情况下我可以使用 coalesce() 吗?
  • @satcha COALESCE 返回值列表中的第一个非空值,它不影响返回的记录。如果您想要第一个非空 ID,您可以使用 COALESCE(d.C_ID,c.C_ID,b.C_ID,a.CID,t.C_ID)。您没有发布实际的表架构、数据或您期望的内容,因此无法创建返回您想要的内容的查询。
  • 你说得对,我刚刚发布了更多细节也许可以帮助谢谢
  • With MyCTE AS ( --Anchor. Get the roots SELECT C_ID, C_ID as ParentID FROM tablex WHERE title is null UNION ALL --Recursive. Get the direct descendants of the "previous" case SELECT t.C_ID, m.ParentID FROM tablex t INNER JOIN MyCTE m on t.ID=v.title ) SELECT ID .ParentID FROM MyCTE 正确答案。
猜你喜欢
  • 2015-01-26
  • 1970-01-01
  • 2018-07-23
  • 2021-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-21
  • 2010-09-19
相关资源
最近更新 更多