选择尊重祖先的订单数据

时间:2015-11-25 00:43:38

标签: sql sql-server

我有一个包含3列的表MyStackFiles

  • FileID(主键)
  • 文件名
  • OriginalFileID(如果没有原始文件或其中一个其他文件ID,则可以为0)

我的目标是选择按名称排序的整个数据。另外,我需要始终让原始文件出现在他们的孩子面前。换句话说,所需的结果将从第一个按字母顺序排列的文件开始,该文件的OriginalFileID为0,后面是其所有子项(如果可用),按字母顺序排列。以下SQL脚本创建示例数据并准确说明我正在尝试实现的目标。请注意,最后一个select命令是所需的输出。 什么是可以返回所需结果的查询?

剧本:

    -------------------------- Creating the Example Schema --------------------------

IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.Tables WHERE Table_Name = 'MyStackFiles')
    Drop table MyStackFiles
GO

CREATE TABLE [dbo].[MyStackFiles](
    [FileID] [int] IDENTITY(1,1) NOT NULL,
    [FileName] [varchar](50) NULL,
    [OriginalFileID] [int] NOT NULL DEFAULT (0),
 CONSTRAINT [PK_MyStackFiles] PRIMARY KEY CLUSTERED 
(
    [FileID] 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

-------------------------- Insert Into the Sample Data --------------------------

INSERT INTO MyStackFiles(FileName) values ('S')
INSERT INTO MyStackFiles(FileName) values ('G')
INSERT INTO MyStackFiles(FileName, OriginalFileID) values ('E', 1)
INSERT INTO MyStackFiles(FileName) values ('F')
INSERT INTO MyStackFiles(FileName, OriginalFileID) values ('Q', 2)
INSERT INTO MyStackFiles(FileName, OriginalFileID) values ('N', 3)
INSERT INTO MyStackFiles(FileName) values ('A')
INSERT INTO MyStackFiles(FileName, OriginalFileID) values ('X', 1)
INSERT INTO MyStackFiles(FileName) values ('W')

------------------------------------------------------------------------------

GO

-------------------------- Simple select sorted by FileName --------------------------

SELECT * From MyStackFiles ORDER BY FileName

-------------------------- A representation of the desired result --------------------------

SELECT * FROM MyStackFiles WHERE FileID = 7 UNION ALL -- We insert "A" (respecting the alphabetical order) since its OriginalFileID is 0
SELECT * FROM MyStackFiles WHERE FileID = 4 UNION ALL -- Then we insert F.
SELECT * FROM MyStackFiles WHERE FileID = 2 UNION ALL -- Then we insert G. G has children so we insert them
SELECT * FROM MyStackFiles WHERE FileID = 5 UNION ALL -- Q is the only child of G. We insert it
SELECT * FROM MyStackFiles WHERE FileID = 1 UNION ALL -- Now we insert S. Notice that S has two children (E and X)
SELECT * FROM MyStackFiles WHERE FileID = 3 UNION ALL -- E is before X alphabetically so it gets inserted first
SELECT * FROM MyStackFiles WHERE FileID = 6 UNION ALL -- E happens to have children so we insert them right away (in a depth first fashion)
SELECT * FROM MyStackFiles WHERE FileID = 8 UNION ALL -- Now we insert the other child of S which is X
SELECT * FROM MyStackFiles WHERE FileID = 9           -- Finally we insert W the only file left


--Drop Table MyStackFiles

如果有助于找到有效的查询,我可以接受任何架构修改。

1 个答案:

答案 0 :(得分:1)

我正在使用名为Recursive CTE的技术来尝试解决您的问题:

with t (RowID, FileID, FileName, OriginalFileID)
as (
    select convert(varchar(max), row_number() over (order by s.FileName)), s.*
    from MyStackFiles s
    where s.OriginalFileID = 0
    union all
    select t.RowID + '.' + convert(varchar(max), row_number() over (order by s.FileName)), s.*
    from MyStackFiles s
    inner join t on t.FileID = s.OriginalFileID
)
select FileID, FileName, OriginalFileID from t
order by RowID

临时创建临时列RowID以将祖先的RowID链接到行的row_number,以便例如文件“N”将具有RowID ='4.1.1',该文件“X”将具有RowID ='4.2',这是要符合您的排序要求的排序列。