【问题标题】:Is my database good for hierarchical data? I want to write a SQL query it with "Where" value我的数据库适合分层数据吗?我想用“Where”值编写一个 SQL 查询
【发布时间】:2017-02-09 02:30:16
【问题描述】:

我的数据库是这样的

**Code** | **Name** | **CodeParent** | **Level**
-XXX-| --TOP-| ----000000----| --0--
-YYY-| --TOP-| ----000000----| --0--
-AAA-| -Lower| ------XXX------| -1-
-BBB-| Lower2| ------AAA------| -2-
-CCC-| -Lower| ------YYY------| -1-

好吧,假设我想从这个表中选择

Select *
from table
where Code = 'XXX'

然后像这样检索数据

**Code** | **Name** | **CodeParent** | **Level**
-XXX-| --TOP-| ----000000----| --0--
-AAA-| -Lower| ------XXX------| -1-
-BBB-| Lower2| ------AAA------| -2-

我一直在寻找一天,但仍然不知道该怎么做。

我的数据库设计够好吗?

我试着选择喜欢

Select * From table where Code = 'XXX'
Union All
Select * From table where CodeParent = 'XXX'

表格没有限制级别

所以,2级后我不知道该怎么做。

【问题讨论】:

  • 仅供参考,您可以搜索recursive cte mssql
  • 在 SQL Server 中有一个层次结构数据类型msdn.microsoft.com/en-us/library/bb677173.aspx,它提供了许多帮助方法。在您的情况下,我相信您可以使用 IsAncestor 助手。但首先您需要将数据加载到这种数据类型中,这很重要。执行您想要的操作的另一种标准方法是分配一个“平面路径”列,该列描述了一个平面字符串中从根开始的整个路径的元素。您只需在字符串上使用LIKE 即可搜索
  • 表示分层数据的一个相对简单的选项是使用nested sets。使用嵌套集,检索数据非常简单高效,但插入/更新可能有点复杂,因此嵌套集可能有意义,也可能没有意义,具体取决于您的要求。
  • 谢谢大家,平面路径法很有意思。
  • 一个现已删除的答案提供this helpful link

标签: sql sql-server vb.net


【解决方案1】:

如果您正在寻找递归 cte,请考虑以下事项:

您可能会注意到层次结构以正确的顺序呈现。您可能还会注意到范围键 (R1/R2)。这些可用于非递归聚合、选择标准和/或导航。将此代码放在 Table-Valued-Function 中可能是明智的选择。

Declare @YourTable table (Code varchar(25),CodeParent  varchar(25),Name varchar(50))
Insert into @YourTable values 
 ('XXX', NULL,'Top')
,('YYY', NULL,'Top')
,('AAA','XXX','Lower')
,('BBB','AAA','Lower 2')
,('CCC','YYY','Lower')

Declare @Top    varchar(25) = null      --<<  Sets top of Hier NULL otherwise specific ID
Declare @Fetch  varchar(25) = null      --<<  Null for Entier Hier try 'BBB'
Declare @Nest   varchar(25) = '|-----'  --<<  Optional: Added for readability

;with cteP as (
      Select Seq  = cast(10000+Row_Number() over (Order by Name) as varchar(500))
            ,Code
            ,CodeParent 
            ,Lvl=1
            ,Name 
      From   @YourTable 
      Where  IsNull(@Top,'') = case when @Top is null then isnull(CodeParent ,'') else Code end
      Union  All
      Select Seq  = cast(concat(p.Seq,'.',10000+Row_Number() over (Order by r.Name)) as varchar(500))
            ,r.Code
            ,r.CodeParent 
            ,p.Lvl+1
            ,r.Name 
      From   @YourTable r
      Join   cteP p on r.CodeParent  = p.Code)
     ,cteR1 as (Select *,R1=Row_Number() over (Order By Seq) From cteP)
     ,cteR2 as (Select A.Code,R2=Max(B.R1) From cteR1 A Join cteR1 B on (B.Seq like A.Seq+'%') Group By A.Seq,A.Code )
     ,cteHB as (
                Select A.R1  
                      ,B.R2
                      ,A.Code
                      ,A.CodeParent 
                      ,A.Lvl
                      ,Name = Replicate(@Nest,A.Lvl-1) + A.Name
                 From cteR1 A
                 Join cteR2 B on A.Code=B.Code
               )
Select Distinct A.*
 From  cteHB A
 Join  cteHB B on B.Code = IsNull(@Fetch,A.Code) and (@Fetch is not null and A.R1 between B.R1 and B.R2 or B.R1 between A.R1 and A.R2) 
 Order By A.R1

当@Top = null 且@Fetch = null

您将获得整个层次结构

当@Top = 'AAA' 且@Fetch = null

你会得到AAA的后代

当@Top = null 且@Fetch = 'CCC'

你会得到CCC的祖先

【讨论】:

  • 谢谢,它非常适合我。但是还有一个问题,从整个层次结构中,如果我只需要显示“XXX”及其子项,该怎么做
  • @PoyZHarmful set (at)Top ='XXX'
【解决方案2】:

用其他样本数据试试这个,然后告诉我。

Declare @YourTable table (Code varchar(25)
CodeParent  varchar(25),Name varchar(50))

Insert into @YourTable values 
 ('XXX', NULL,'Top')
,('YYY', NULL,'Top')
,('AAA','XXX','Lower')
,('BBB','AAA','Lower 2')
,('CCC','YYY','Lower')
declare @input varchar(25)='XXX'
;with CTE as
(
select *,0 [Level] from @YourTable
where code=@input
union ALL
select t.code,t.CodeParent,t.Name
,[Level]+1
 from @YourTable t
inner join cte c on c.code=t.CodeParent
)

select * from CTE

【讨论】:

    猜你喜欢
    • 2018-06-15
    • 2021-10-07
    • 2017-07-28
    • 1970-01-01
    • 1970-01-01
    • 2019-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多