[英]More advanced logic for ordering results of a query in T-SQL?
我目前正在編寫一個SQL查詢,該查詢應顯示建築物內部具有區域,子區域等的區域的樹狀視圖。不幸的是,我無法模仿某些軟件工具所使用的順序。 我僅限於使用MS SQL 2000,因此順序問題變得更加復雜,此時我已經不知所措。
排序邏輯是“子”列和“父”列相關。 如果第一行的“子級”列的值與第二行的“父級”列匹配,則第二行將排在第一行之后。
--How it currently returns data
Child Level Parent
562 Campus 0
86 Area 1
87 Area 1
88 Area 1
90 Sub-Area 86
91 Sub-Area 86
92 Sub-Area 87
93 Sub-Area 87
94 Sub-Area 88
95 Sub-Area 88
3 Unit 90
16 Unit 90
4 Unit 91
6 Unit 91
etc, so on and therefore
--How I want it to return the data
Child Level Parent
562 Campus 0
1 Building 562
86 Area 1
90 Sub-Area 86
91 Sub-Area 86
87 Area 1
95 Sub-Area 87
95 Sub-Area 87
為了使此邏輯正常工作,需要執行以下操作
如果使用SQL實際上可行嗎?
我很想知道是否會這樣,因為我不願意在此上花更多的時間,除非我知道這實際上是可能的。 我意識到我可以為ORDER BY語句編寫帶有自定義映射的CASE語句,但不適用於其他任何校園(父/子代碼不同),我希望能夠重用此代碼將來只需最少的自定義。
謝謝!
編輯:按要求添加查詢
DECLARE
@BuildingType int,
@CampusType int
SET @BuildingType= 4
SET @CampusType= 1
select
b.fkabc_building_child,
(select isnull(c.collectionname, 'none')
from abc_collections c
where c.pkabc_collections = b.fkabc_building_child) as 'Child Collection',
l.floorname,
isnull(b.fkabc_collections_parent,0) as fkabc_collections_parent,
b.fkabc_floorbreakdowns
from abc_breakdowns r
left join abc_floorbreakdowns fr
on fr.pkabc_floorbreakdowns = b.fkabc_floorbreakdowns
inner join abc_buildingtypescampustypes btct
on btct.pkabc_buildingtypescampustypes = fr.fkabc_buildingtypescampustypes
inner join abc_buildingtypes bt
on btct.fkabc_buildingtypes = bt.pkabc_buildingtypes
inner join abc_collectiontypes ct
on btct.fkabc_collectiontypes = ct.pkabc_collectiontypes
inner join abc_collections c
on b.fkabc_building_child = c.pkabc_collections
inner join abc_floors l
on l.pkabc_floors = c.fkabc_floors
where bt.pkabc_buildingtypes = @BuildingType
and ct.pkabc_collectiontypes = @CampusType
像這樣:
-- prepare some test data
declare @table table (Child int, [Level] varchar(30), Parent int)
insert @table values (562 , 'Campus ', 0 )
insert @table values (1 , 'Building', 562)
insert @table values (86 , 'Area ', 1 )
insert @table values (87 , 'Area ', 1 )
insert @table values (88 , 'Area ', 1 )
insert @table values (90 , 'Sub-Area', 86 )
insert @table values (91 , 'Sub-Area', 86 )
insert @table values (92 , 'Sub-Area', 87 )
insert @table values (93 , 'Sub-Area', 87 )
insert @table values (94 , 'Sub-Area', 88 )
insert @table values (95 , 'Sub-Area', 88 )
insert @table values (3 , 'Unit ', 90 )
insert @table values (16 , 'Unit ', 90 )
insert @table values (4 , 'Unit ', 91 )
insert @table values (6 , 'Unit ', 91 )
select
a.Child, a.[Level], a.Parent
, Campus =
case a.[Level]
when 'Unit' then e.Child
when 'Sub-Area' then d.Child
when 'Area' then c.Child
when 'Building' then b.Child
when 'Campus' then a.Child
end
, Building =
case a.[Level]
when 'Unit' then d.Child
when 'Sub-Area' then c.Child
when 'Area' then b.Child
when 'Building' then a.Child
end
, Area =
case a.[Level]
when 'Unit' then c.Child
when 'Sub-Area' then b.Child
when 'Area' then a.Child
end
, Sub_Area =
case a.[Level]
when 'Unit' then b.Child
when 'Sub-Area' then a.Child
end
, Unit =
case a.[Level]
when 'Unit' then a.Child
end
from @table a
left join @table b on a.Parent = b.Child
and ((a.[Level] = 'Unit' and b.[Level] = 'Sub-Area')
or (a.[Level] = 'Sub-Area' and b.[Level] = 'Area' )
or (a.[Level] = 'Area' and b.[Level] = 'Building')
or (a.[Level] = 'Building' and b.[Level] = 'Campus' ))
left join @table c on b.Parent = c.Child
and ((b.[Level] = 'Sub-Area' and c.[Level] = 'Area' )
or (b.[Level] = 'Area' and c.[Level] = 'Building')
or (b.[Level] = 'Building' and c.[Level] = 'Campus' ))
left join @table d on c.Parent = d.Child
and ((c.[Level] = 'Area' and d.[Level] = 'Building')
or (c.[Level] = 'Building' and d.[Level] = 'Campus' ))
left join @table e on d.Parent = e.Child
and ((d.[Level] = 'Building' and e.[Level] = 'Campus' ))
order by
4, 5, 6, 7, 8
可能有一個比較聰明的方法,不需要重復,但是現在卻暗示了我。
現在,此代碼僅用於演示,以說明查詢的工作方式。 SELECT中不需要5個排序字段,您可以將它們移至ORDER BY。 並且您不應該在ORDER BY中使用順序位置。
但是,您確實需要4個聯接和條件聯接邏輯,才能為每個孩子拉出父級。 而且您確實需要CASE語句,才能為每個級別提取排序鍵。
也許您可以將SELECT語句包裝在派生表中,然后將ORDER BY移至外部查詢。 例如:
SELECT Child, [Level], Parent
FROM (
SELECT ....
) a
ORDER BY Campus, Building, Area, Sub_Area, Unit
這是一種方法; 非常程序化。 不幸的是,在SQL Server 2000上,除非您使用像Peter的解決方案(限於5個級別並將級別的類型硬編碼到查詢本身中(混合數據和元數據) )。 您必須權衡這些限制與任何可觀察到的性能差異。
請注意,我沒有為循環引用添加任何處理,因此希望您可以防止這種情況以其他方式發生。
SET NOCOUNT ON;
GO
DECLARE @foo TABLE
(
AreaID INT PRIMARY KEY,
[Level] SYSNAME,
ParentAreaID INT
);
INSERT @foo
SELECT 562, 'Campus', 0
UNION ALL SELECT 86, 'Area', 1
UNION ALL SELECT 87, 'Area', 1
UNION ALL SELECT 88, 'Area', 1
UNION ALL SELECT 90, 'Sub-Area', 86
UNION ALL SELECT 91, 'Sub-Area', 86
UNION ALL SELECT 92, 'Sub-Area', 87
UNION ALL SELECT 93, 'Sub-Area', 87
UNION ALL SELECT 94, 'Sub-Area', 88
UNION ALL SELECT 95, 'Sub-Area', 88
UNION ALL SELECT 3, 'Unit', 90
UNION ALL SELECT 16, 'Unit', 90
UNION ALL SELECT 4, 'Unit', 91
UNION ALL SELECT 6, 'Unit', 91
UNION ALL SELECT 1, 'Building', 562;
DECLARE @nest TABLE
(
NestID INT IDENTITY(1,1) PRIMARY KEY,
AreaID INT,
[Level] INT,
ParentNestID INT,
AreaIDPath VARCHAR(4000)
);
DECLARE @rc INT, @l INT;
SET @l = 0;
INSERT @nest(AreaID, [Level], AreaIDPath)
SELECT AreaID, 0, CONVERT(VARCHAR(12), AreaID)
FROM @foo
WHERE ParentAreaID = 0;
SELECT @rc = @@ROWCOUNT;
WHILE @rc >= 1
BEGIN
SELECT @l = @l + 1;
INSERT @nest(AreaID, [Level], ParentNestID)
SELECT f.AreaID, @l, n.NestID
FROM @foo AS f
INNER JOIN @nest AS n
ON f.ParentAreaID = n.AreaID
AND n.[Level] = @l - 1;
SET @rc = @@ROWCOUNT;
UPDATE n
SET n.AreaIDPath = COALESCE(n2.AreaIDPath, '')
+ '\' + CONVERT(VARCHAR(12), n.AreaID) + '\'
FROM @nest AS n
INNER JOIN @nest AS n2
ON n.ParentNestID = n2.NestID
WHERE n.[Level] = @l
AND n2.AreaIDPath NOT LIKE '%\' + CONVERT(VARCHAR(12), n.AreaID) + '\%';
END
SELECT
structure = REPLICATE(' - ', n.[Level]) + RTRIM(f.AreaID),
f.AreaID, f.[Level], f.ParentAreaID
FROM @nest AS n
INNER JOIN @foo AS f
ON n.AreaID = f.AreaID
ORDER BY n.AreaIDPath;
這確實是SQL Server 2005中的遞歸CTE設計的目的。 (從本質上來說,這仍然是一個游標,但是語法比上面的混亂要干凈得多。)在可以升級到SQL Server 2005之前,如果使用表示層來遍歷結果集並適當地對事物進行排序,可能會更好。這太復雜了,無法引入您的查詢操作。
我將不得不花更多的時間來研究它,以了解細節...但是,如果您使用的是SQL Server 2005(或2008),則建議使用公用表表達式(CTE)。 這使您可以遞歸地構建查詢。 因此您可以獲取建築物,然后獲取其所有子項以添加到列表中。 您可能能夠提出一種編號方案等,以使用CTE以正確的順序獲取條目。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.