SQL服务器查询,对多列进行排序

时间:2018-02-07 10:37:52

标签: sql sql-server sorting

我们有一个嵌套的任务结构,其中每个任务都可以包含其他任务。任务中的任务顺序很重要,并由从<0开始的序列字段定义。 这是我的表结构:

USE [MyDB]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Relation](
    [PK_ID] [int] IDENTITY(1,1) NOT NULL,
    [SourceEntityId] [uniqueidentifier] NOT NULL,
    [TargetEntityId] [uniqueidentifier] NOT NULL,
 CONSTRAINT [PK_Relation] PRIMARY KEY CLUSTERED 
(
    [PK_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

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[TaskTable1](
    [Id] [uniqueidentifier] NOT NULL,
    [Title] [nvarchar](max) NULL,
    [SequenceId] [int] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[TaskTable2](
    [Id] [uniqueidentifier] NOT NULL,
    [Title] [nvarchar](max) NULL,
    [SequenceId] [int] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO
SET IDENTITY_INSERT [dbo].[Relation] ON 

GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (1, N'dab00c89-961c-84dd-bb43-cffd18e63594', N'5b266fd1-cbc8-c16a-91c4-5675a35c9ecf')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (2, N'dab00c89-961c-84dd-bb43-cffd18e63594', N'e499ca68-8103-b8ec-06ba-110fa3f6eb5b')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (4, N'dab00c89-961c-84dd-bb43-cffd18e63594', N'645ad2eb-df10-0d5b-0526-408aad45a145')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (5, N'785227d1-393c-ae18-02e5-03ab08d577af', N'5655aeb7-b8b5-dca9-38af-37687c668c14')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (6, N'dab00c89-961c-84dd-bb43-cffd18e63594', N'030cdefc-0e45-01e6-e2a5-a69e303bda4b')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (7, N'dab00c89-961c-84dd-bb43-cffd18e63594', N'0375c7a1-8cc5-a4c8-151c-966e4af83f73')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (8, N'dab00c89-961c-84dd-bb43-cffd18e63594', N'785227d1-393c-ae18-02e5-03ab08d577af')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (9, N'030cdefc-0e45-01e6-e2a5-a69e303bda4b', N'8324bba9-252f-bef8-c018-8b86491e2361')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (10, N'030cdefc-0e45-01e6-e2a5-a69e303bda4b', N'f1cbe8a3-3285-4cf0-096d-aad0327bdb0b')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (11, N'dab00c89-961c-84dd-bb43-cffd18e63594', N'0189f0af-5045-a498-2d70-99187bf3f0ae')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (12, N'785227d1-393c-ae18-02e5-03ab08d577af', N'ffecd091-c17b-ee5f-a64d-54ea9ff65aa9')
GO

SET IDENTITY_INSERT [dbo].[Relation] OFF
GO
INSERT [dbo].[TaskTable1] ([Id], [Title], [SequenceId]) VALUES (N'5b266fd1-cbc8-c16a-91c4-5675a35c9ecf', N'First', 0)
GO
INSERT [dbo].[TaskTable1] ([Id], [Title], [SequenceId]) VALUES (N'e499ca68-8103-b8ec-06ba-110fa3f6eb5b', N'Second', 1)
GO
INSERT [dbo].[TaskTable1] ([Id], [Title], [SequenceId]) VALUES (N'0189f0af-5045-a498-2d70-99187bf3f0ae', N'Fourth', 3)
GO
INSERT [dbo].[TaskTable1] ([Id], [Title], [SequenceId]) VALUES (N'0375c7a1-8cc5-a4c8-151c-966e4af83f73', N'Sixth', 5)
GO
INSERT [dbo].[TaskTable2] ([Id], [Title], [SequenceId]) VALUES (N'030cdefc-0e45-01e6-e2a5-a69e303bda4b', N'Fifth', 4)
GO
INSERT [dbo].[TaskTable2] ([Id], [Title], [SequenceId]) VALUES (N'785227d1-393c-ae18-02e5-03ab08d577af', N'Seventh', 6)
GO
INSERT [dbo].[TaskTable2] ([Id], [Title], [SequenceId]) VALUES (N'645ad2eb-df10-0d5b-0526-408aad45a145', N'Third', 2)
GO
INSERT [dbo].[TaskTable2] ([Id], [Title], [SequenceId]) VALUES (N'8324bba9-252f-bef8-c018-8b86491e2361', N'sub1', 0)
GO
INSERT [dbo].[TaskTable2] ([Id], [Title], [SequenceId]) VALUES (N'f1cbe8a3-3285-4cf0-096d-aad0327bdb0b', N'sub2', 1)
GO
INSERT [dbo].[TaskTable1] ([Id], [Title], [SequenceId]) VALUES (N'ffecd091-c17b-ee5f-a64d-54ea9ff65aa9', N'sub 1', 0)
GO
INSERT [dbo].[TaskTable1] ([Id], [Title], [SequenceId]) VALUES (N'5655aeb7-b8b5-dca9-38af-37687c668c14', N'sub 2', 1)
GO

为了让他们的子任务在他们父母的正下方顺序完成任务,我尝试了以下查询无济于事:

;With TaskCTE 
AS
(
    select R.SourceEntityId AS ParentTask_Id, R.TargetEntityId AS Task_Id , cast(null as uniqueidentifier) AS ParentTask, 0 AS Level
     , ROW_NUMBER() OVER (ORDER BY (SELECT 100)) / power(10.0,0) as x
     from Relation R
        where (R.SourceEntityId = 'DAB00C89-961C-84DD-BB43-CFFD18E63594')
    UNION ALL
    select R1.SourceEntityId , R1.TargetEntityId, TaskCTE.Task_Id  , Level + 1 
    , x + ROW_NUMBER() OVER (ORDER BY (SELECT 100)) / power(10.0,level+1)
    from Relation R1
        INNER JOIN TaskCTE
            ON R1.SourceEntityId = TaskCTE.Task_Id  
)

select ParentTask_Id, Task_Id, ParentTask, Level 
, COALESCE(TT1.Title, TT2.Title) AS Title
, COALESCE(TT1.SequenceId, TT2.SequenceId) AS SequenceId
, x
from TaskCTE
LEFT OUTER JOIN TaskTable1 TT1 
ON TaskCTE.Task_Id = TT1.Id
LEFT OUTER JOIN TaskTable2 TT2
ON TaskCTE.Task_Id = TT2.Id

order by level , SequenceId

如果您遵循所需输出的结构(如下图所示),序列**列以及**级别列必须确定排序顺序。

提前致谢

required output

编辑:我的查询输出错误: enter image description here

3 个答案:

答案 0 :(得分:1)

如果您的问题是其他表中的序列字段而不是关系表,那么为什么不在运行递归之前加入它们呢?但它可能会比您的初始查询慢。这是一个样本

with cte as (
    select 
        r.SourceEntityId, r.TargetEntityId, t.SequenceId, 0 k
    from 
        Relation r
        join (
            select * from TaskTable1
            union all
            select * from TaskTable2
        ) t on r.TargetEntityId = t.id


    ---------------------------------------        
    union all select * from cte where k = 1
    ---------------------------------------
)
, rcte as (
    select
        SourceEntityId, TargetEntityId, ParentTask = cast(null as uniqueidentifier)
        , SequenceId, rn = cast(row_number() over (order by SequenceId) as varchar(8000)), 1 step
    from
        cte
    where
        SourceEntityId = 'DAB00C89-961C-84DD-BB43-CFFD18E63594'
    union all
    select
        a.TargetEntityId, b.TargetEntityId, a.SourceEntityId, b.SequenceId
        , cast(concat(a.rn, '.', row_number() over (partition by b.SourceEntityId order by b.SequenceId)) as varchar(8000))
        , step + 1
    from
        rcte a
        join cte b on a.TargetEntityId = b.SourceEntityId
)
select
    *
from
    rcte
order by rn

我没有收录您的X列,我无法得到想要计算的内容。此外,您预期的ParentTaskParentTask_Id输出值相同。应该这样吗?

答案 1 :(得分:1)

我使用与@Uzi相同的查询进行微调。我对他有同样的怀疑。@ Yasser应该清楚地显示正确输出的输出是什么,并删除不必要的列。

如果row_number仅用于订购记录,那么为什么要将其转换为varchar(8000)。此外,您可以一起避免expensive Row_number

利用PK_ID而不是昂贵的row_number,即使在这种情况下PK_ID不是顺序的。

如果性能是一个大问题,那么用户应该在3表中提及行数以及在何处以何种情况应用其他过滤器?

为什么数据类型为uniqueidentifier?如果它是INT,它会解决目的吗? Read this

检查此查询,

     WITH cte
    AS (
        SELECT r.PK_ID
            ,r.SourceEntityId
            ,r.TargetEntityId
            ,t.SequenceId,0 k
        FROM #Relation r
        JOIN (
            SELECT id
                ,SequenceId
            FROM #TaskTable1

            UNION ALL

            SELECT id
                ,SequenceId
            FROM #TaskTable2
            ) t ON r.TargetEntityId = t.id

             ---------------------------------------        
        --union all select * from cte where k = 1
        ---------------------------------------
        )
        ,rcte
    AS (
        SELECT SourceEntityId
            ,TargetEntityId
            ,ParentTask = cast(NULL AS UNIQUEIDENTIFIER)
            ,SequenceId
            , rn = cast(row_number() over (order by SequenceId) as decimal(3,1))
            --, rn = cast( SequenceId+1 as decimal(3,1))--**
            ,1 step
        FROM cte
        WHERE SourceEntityId = 'DAB00C89-961C-84DD-BB43-CFFD18E63594'

        UNION ALL

        SELECT a.TargetEntityId
            ,b.TargetEntityId
            ,a.SourceEntityId
            ,b.SequenceId

                ,cast((a.rn+(b.SequenceId/10.0)) as  decimal(3,1))
            ,step + 1
        FROM rcte a
        JOIN cte b ON a.TargetEntityId = b.SourceEntityId

        )

    SELECT *

    FROM rcte
    ORDER BY rn
--**
--SELECT *

--FROM rcte
--ORDER BY rn,st

- 第二次编辑,

据我所知,无法更改数据库。 在这种情况下,创建索引视图是非常合理的,其中任务表id是Clustered index。

  select id, SequenceId from #TaskTable1
  union all
  select id, SequenceId from #TaskTable2



     Create nonclustered index NCI_Relation_SourceID on Relation([SourceEntityId])
 Create nonclustered index NCI_Relation_TargetEntityId on Relation([TargetEntityId])

你可以尝试这种组合,

将PK_ID作为聚簇索引删除,并将TargetEntityId作为聚簇索引。

您可以尝试在此查询上创建视图,

SELECT r.PK_ID
        ,r.SourceEntityId
        ,r.TargetEntityId
        ,t.SequenceId
    FROM #Relation r
    JOIN (
        SELECT id
            ,SequenceId
        FROM #TaskTable1

        UNION ALL

        SELECT id
            ,SequenceId
        FROM #TaskTable2
        ) t ON r.TargetEntityId = t.id

答案 2 :(得分:0)

在CTE表达式中添加一个名为Hierarchy的新列,并根据此值排序结果可以解决您的需求

以下是修改后的CTE查询

;With TaskCTE AS
(
    select 
    R.SourceEntityId AS ParentTask_Id, 
    R.TargetEntityId AS Task_Id , cast(null as uniqueidentifier) AS ParentTask, 0 AS Level
     , ROW_NUMBER() OVER (ORDER BY (SELECT 100)) / power(10.0,0) as x
     ,CAST( ROW_NUMBER() OVER (ORDER BY R.SourceEntityId) as varchar(max)) Hierarchy
     from Relation R
        where (R.SourceEntityId = 'DAB00C89-961C-84DD-BB43-CFFD18E63594')


    UNION ALL

    select R1.SourceEntityId , R1.TargetEntityId, TaskCTE.Task_Id  , Level + 1 
    , x + ROW_NUMBER() OVER (ORDER BY (SELECT 100)) / power(10.0,level+1)
    ,CAST(Hierarchy + ':' + CAST(ROW_NUMBER() OVER (ORDER BY R1.SourceEntityId) as varchar(max)) as varchar(max)) as Hierarchy
    from Relation R1
        INNER JOIN TaskCTE
            ON R1.SourceEntityId = TaskCTE.Task_Id  
)

select ParentTask_Id, Task_Id, ParentTask, Level 
, COALESCE(TT1.Title, TT2.Title) AS Title
, COALESCE(TT1.SequenceId, TT2.SequenceId) AS SequenceId
, x
,Hierarchy
from TaskCTE
LEFT OUTER JOIN TaskTable1 TT1 
ON TaskCTE.Task_Id = TT1.Id
LEFT OUTER JOIN TaskTable2 TT2
ON TaskCTE.Task_Id = TT2.Id

order by Hierarchy 

请注意,我添加了Hierarchy列,其值使用ROW_NUMBER()函数计算,该函数为每个任务创建唯一的整数值

您可以在refereced教程中找到此hierarchy query with SQL CTE的实现 我希望它有所帮助

我还在此处添加输出截图,以显示如何根据层次结构对数据进行排序

虽然孩子是在父母之后列出的,但是与我想要的结果没有一对一的匹配,我可以看到

enter image description here