Sql选择使用CTE来排序递归数据

时间:2017-03-26 20:23:40

标签: sql sql-server recursion common-table-expression recursive-query

请在SQL Server中使用CTE

解决此问题

情况示例

Equation 0 = 0.25*Equation 1
Equation 1 = Equation 2 + Equation 3 + 0.5*Equation 5
Equation 2 = 15 + 40
Equation 3 = Equation 6 + Equation 7
Equation 4 = 10
Equation 5 = 10 + Equation 4
Equation 6 = 10 +5
Equation 7 = Equation 5 + Equation 2

表的结构是

元素表

ID     | Name
-------|--------------
0      | Equation 0
1      | Equation 1
2      | Equation 2
3      | Equation 3
4      | Equation 4
5      | Equation 5
6      | Equation 6
7      | Equation 7
---------------------

该表包含每个等式的所有项目

等式表

FK     |    Item   |    Type
-------|-----------|------------------
0      |    0.25   |    constant
0      |    *      |    Operator
0      |    1      |    Element
1      |    2      |    Element
1      |    +      |    Operator
1      |    3      |    Element
1      |    +      |    Operator
1      |    0.5    |    constant
1      |    *      |    Operator
1      |    5      |    Element
2      |    15     |    constant
2      |    +      |    Operator
2      |    40     |    constant
…      |           |      
…      |           | 
… etc  |           |        
------------------------------------

如果类型是元素,则表示它是元素项

是否有任何sql语句结果为正确的顺序,我必须使用它来逐个计算这些方程而不使用递归函数,因为它在SQL中是有限的 另一种方法是计算没有任何要求的最后一个方程,然后计算上面的方程式,因为我需要一个方程式,我发现它已经计算而没有递归方程式

我需要sql select语句来生成以下顺序

Equation 2
Equation 6
Equation 4
Equation 5
Equation 7
Equation 3
Equation 1
Equation 0
我用眼睛命令它们,因为这是一个简单的例子 是否有任何select语句用于这样做 或者用户必须手动订购???

  • ...更新

    1。完整的测试场景

创建表格的脚本

/****** Object:  Table [dbo].[Element]    Script Date: 26/03/2017 11:10:10 م ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Element](
    [Id] [int] NOT NULL,
    [Name] [nvarchar](50) NOT NULL,
 CONSTRAINT [PK_Element] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[Equation]    Script Date: 26/03/2017 11:10:10 م ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Equation](
    [fk] [int] NOT NULL,
    [Item] [nvarchar](50) NOT NULL,
    [Type] [nvarchar](50) NOT NULL
) ON [PRIMARY]

GO
INSERT [dbo].[Element] ([Id], [Name]) VALUES (0, N'Equation 0')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (1, N'Equation 1')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (2, N'Equation 2')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (3, N'Equation 3')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (4, N'Equation 4')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (5, N'Equation 5')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (6, N'Equation 6')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (7, N'Equation 7')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (0, N'0.25', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (0, N'*', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (0, N'1', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'2', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'3', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'0.5', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'*', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'5', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (2, N'15', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (2, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (2, N'40', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (3, N'6', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (3, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (3, N'7', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (4, N'10', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (5, N'10', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (5, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (5, N'4', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (6, N'10', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (6, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (6, N'5', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (7, N'5', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (7, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (7, N'2', N'Element')
  1. *
  2.   

    @Gordon Linoff

    • ...非常感谢您的关心,但我发现一些错误使用了我无法解决的提供的脚本,因为这是我第一次使用CTE

    第二个脚本给了我一些我无法解决的错误 enter image description here

    第一个脚本也给了我错误,我无法解决 enter image description here

2 个答案:

答案 0 :(得分:3)

你可以这样试试:

WITH Related AS
(
    SELECT *
    FROM Equation AS eq
    LEFT JOIN Element AS e ON eq.[Type]='Element' AND eq.Item=CAST(e.Id AS VARCHAR(10))
    WHERE eq.[Type]='Element' 
)
,Dependecies AS
(
    SELECT e.*
          ,ISNULL(r.Name,'') AS DepName 
    FROM Element AS e
    LEFT JOIN Related AS r ON e.Id=r.fk
)
,recCTE AS
(
    SELECT 1 AS lvl,d.Id,d.Name,d.DepName
    FROM Dependecies AS d
    WHERE d.Name NOT IN(SELECT x.DepName FROM Dependecies AS x)

    UNION ALL

    SELECT r.lvl+1,d.Id,d.Name,d.DepName
    FROM recCTE AS r
    INNER JOIN Dependecies AS d ON r.DepName=d.Name

)
,Ranked AS
(
    SELECT Name
            ,DENSE_RANK() OVER(ORDER BY CASE WHEN DepName='' THEN 1000 ELSE lvl END DESC) AS Rnk
    FROM recCTE
)
SELECT Name,MIN(Rnk) AS Rnk
FROM Ranked
GROUP BY Name
ORDER BY Min(Rnk)

结果

Equation 2  1
Equation 4  1
Equation 6  1
Equation 5  2
Equation 7  3
Equation 3  4
Equation 1  5
Equation 0  6

说明

有一份CTE清单:

  • 第一个CTE会将Elements绑定到Equation行,其类型为Element
  • 第二个将列出所有具有依赖关系的元素
  • 第三个CTE是一个递归CTE,从没有任何依赖的元素开始,沿着依赖路径工作
  • 下一个CTE使用DENSE_RANK() OVER()来获取订购的电话

最终SELECT会返回每个元素及其最早的时刻。

答案 1 :(得分:0)

哦,如果我们能够将其表达为:

,那就会膨胀
with cte as (
      select e.fk, 1 as lev
      from equation e
      group by e.fk
      having sum(case when type = 'Element' then 1 else 0 end) = 0
      union all
      select e.fk, max(cte.lev) + 1
      from equation e left join
           cte
           on e.fk = cte.fk
      group by e.fk
      having count(*) = count(cte.fk)
     )

但这是不可能的。所以,我们必须考虑字符串操作(我认为)。这导致将依赖项放在字符串中并重复地从字符串中删除元素。如果我有这个权利:

with eq as (
       select e.fk,
              stuff( (select ',' + e2.item
                      from equation e2
                      where e2.fk = e.fk and e2.type = 'Element'
                      order by e2.item
                      for xml path ('')
                     ), 1, 1, '') as elements 
       from (select distinct e.fk from equation e) e
      )
      select e.fk, '' as elements_found, 1 as lev
      from eq
      where elements = ''
      union all
      select eq.fk, substring(elements_found, charindex(',', elements_found + ',') + 1), 2 as lev
      from eq join
           cte
           on cte.elements_found like eq.fk + ',%' and eq.fk = cte.fk
      where eq.type = 'Element'
     )
select cte.fk, max(lev)
from cte
group by cte.fk
order by max(lev);