在 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
I am currently writing a SQL query that should display a tree-view of areas inside a building with areas, sub-areas, etc. Unfortunately I have been unable to mimic the ordering used by some of our software tools. I'm restricted to MS SQL 2000 so the question of order becomes much more complicated and I'm just over my head at this point.
The ordering logic is that the Child column and Parent column are related. If the value of the 1st row's Child column matches the 2nd row's Parent column, then the 2nd row goes after the first.
--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
For this logic to work correctly it would need to do something like
- Return the building rows with their Parent and Child codes
- Match Area Parent codes to the building Child codes, then insert Area rows under the appropriate Building row.
- Match Sub-Area Parent codes to the Area Child codes, then insert Sub-Area rows under the appropriate Area.
- Match Unit Parent codes to the Sub-Area Child codes, then insert the Unit rows under the appropriate Sub-Area
If this actually possible with SQL?
I would love to know if it is as I'm hesitant to invest any more time into this unless I know it's actually a possibility. I realize that I could write a CASE statement with a custom mapping for an ORDER BY statement, but that won't work for any other campus (parent/child codes are different) and I would love to be able to re-use this code in the future with minimal customization.
Thanks!
EDIT: Adding Query as requested
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
像这样的事情:
可能有一种更聪明的方法来减少重复,但它现在暗示了我。
现在,此代码仅用于演示,以说明查询是如何工作的。 SELECT 中不需要有 5 个排序字段,可以将它们移动到 ORDER BY 中。并且您不应该在 ORDER BY 中使用序数位置。
但您确实需要 4 个联接和条件联接逻辑来提取每个子级的父级。并且您确实需要 CASE 语句来提取每个级别的排序键。
也许您可以将 SELECT 语句包装在派生表中,并将 ORDER BY 移至外部查询。例如:
Something like this:
There's probably a cleverer way to do it w/less repetition, but it alludes me for now.
Now, this code is just for demonstration, to illustrate how the query works. You don't need to have 5 sort fields in the SELECT, you can move them to the ORDER BY. And you shouldn't use ordinal positions in the ORDER BY.
But you do need the 4 joins, and the conditional join logic, to pull out the parent levels for each child. And you do need the CASE statements, to pull out the sort key for each level.
Perhaps you could wrap the SELECT statement in a derived table, and move the ORDER BY to the outer query. eg:
这是一种方法;非常程序化。不幸的是,在 SQL Server 2000 上,我认为您无法摆脱游标,除非您使用像 Peter 那样的解决方案,该解决方案仅限于 5 个级别,并将级别类型硬编码到查询本身中(混合数据和元数据) )。您必须权衡这些限制与任何可观察到的性能差异。
请注意,我没有添加任何对循环引用的处理,因此希望您可以通过其他方式防止这种情况发生。
这确实是 SQL Server 2005 中递归 CTE 的设计目的。 (这本质上仍然是一个游标,但语法比上面的混乱要干净得多。)在升级到 SQL Server 2005 之前,您可能会更幸运,只需使用表示层循环结果集并适当地排序,如果这太复杂了,无法引入到您的查询操作中。
Here's one approach; very procedural. Unfortunately on SQL Server 2000 I don't think you'll be able to get away from cursors unless you use a solution like Peter's which is limited to 5 levels and hard-codes the types of levels into the query itself (mixing data and metadata). You'll have to weigh these limitations with any observable performance difference.
Note that I didn't add any handling for circular references, so hopefully you are preventing that from happening in other ways.
This really is what recursive CTEs in SQL Server 2005 were designed for. (This is still essentially a cursor, but the syntax is much cleaner than the above mess.) Until you can upgrade to SQL Server 2005, you might have better luck simply using the presentation tier to loop over the resultset and order things appropriately, if this is too complex to introduce to your query operations.
我将不得不花更多的时间来研究它以找出详细信息...但是,如果您使用的是 SQL Server 2005(或 2008),我建议您考虑使用通用表表达式(CTE)。这使您可以递归地构建查询;因此您可以获取建筑物,然后获取其所有子建筑以添加到列表中。您也许能够想出一个编号方案等,以便使用 CTE 以正确的顺序获取条目。
I would have to spend more time looking into it to figure out the details... but, if you are using SQL Server 2005 (or 2008), I would suggest looking into using a Common Table Expression (CTE). This lets you build the query recursively; so you can fetch a building, then fetch all of its children to add in to the list. You may be able to come up with a numbering scheme or the like to get the entries in the proper order using a CTE.