Bee*_*ems 4 t-sql sql-server sql-server-2008-r2
我正在使用SQL Server 2008 R2,我有一个复杂的订购问题或问题,我无法找到解决方案.
为了更好地解释,我在下面发布了一个样本结果查询.在这里,我们试图显示位置的层次结构,但是当父/子关系被正确排序时,它们在它们的关系中不是按字母顺序排列的.如您所见,"东海岸"和"西海岸"都是顶级位置,因为它们的父位置(f_locationparent)等于(0).但是,我想在"西海岸"之前展示"东海岸".很显然,我不能简单地通过订购f_locationname,然后由f_lineage,因为关系会那么不正确的顺序显示.重要说明:顶级位置的父位置始终为(0),因为它们没有父级.
f_locationid f_locationparent f_locationname f_level f_lineage
-------------------------------------------------------------------------
4 0 West Coast 0 0_4
5 4 Los Angeles 1 0_4_5
6 5 Del Rey 2 0_4_5_6
7 5 Reseda 2 0_4_5_7
8 5 Crenshaw 2 0_4_5_8
9 0 East Coast 0 0_9
10 9 New York City 1 0_9_10
1 10 Queens 2 0_9_10_1
2 10 Bronx 2 0_9_10_2
3 10 Manhattan 2 0_9_10_3
Run Code Online (Sandbox Code Playgroud)
以下是当前查询:
;WITH cte_locationlineage AS
(
SELECT a.f_locationid, a.f_locationparent, a.f_locationname, 0 AS f_level,
CONVERT(varchar(30), '0_' + convert(varchar(10), f_locationid)) f_lineage
FROM tb__templocations a
WHERE f_locationparent = '0'
UNION ALL
SELECT a.f_locationid,
a.f_locationparent,
a.f_locationname,
c.f_level + 1,
CONVERT(varchar(30), f_lineage + '_'
+ convert(varchar(10), a.f_locationid))
FROM cte_locationlineage c
JOIN tb__templocations a
ON a.f_locationparent = c.f_locationID
)
SELECT *
FROM cte_locationlineage c
ORDER BY f_lineage
Run Code Online (Sandbox Code Playgroud)
如您所见,它基于沿袭排序,后者是位置ID(f_locationID)的组合.不幸的是,正如您所看到的,位置ID并不总是按字母顺序排列.
这是一个SQL小提琴,所以你可以看到它是如何工作的.
最后,使用相同的数据,这是我想看到的结果查询,在父项下的关系中,项按字母顺序排序.因此,对于"东海岸"祖父母和"纽约市"的父母,其下列出的孩子是按字母顺序排列的.
f_locationid f_locationparent f_locationname f_level f_lineage
-------------------------------------------------------------------------
9 0 East Coast 0 0_9
10 9 New York City 1 0_9_10
2 10 Bronx 2 0_9_10_2
3 10 Manhattan 2 0_9_10_3
1 10 Queens 2 0_9_10_1
4 0 West Coast 0 0_4
5 4 Los Angeles 1 0_4_5
8 5 Crenshaw 2 0_4_5_8
6 5 Del Rey 2 0_4_5_6
7 5 Reseda 2 0_4_5_7
Run Code Online (Sandbox Code Playgroud)
Jas*_*ish 10
你可以ROW_NUMBER()用来帮助:
;WITH cte_locationlineage AS
(
SELECT a.f_locationid, a.f_locationparent, a.f_locationname, 0 AS f_level,
CONVERT(varchar(30), '0_' + convert(varchar(10), f_locationid)) f_lineage,
CAST(ROW_NUMBER() OVER(ORDER BY f_locationname) as decimal(8,4)) as ordering
FROM tb__templocations a
WHERE f_locationparent = '0'
UNION ALL
SELECT a.f_locationid,
a.f_locationparent,
a.f_locationname,
c.f_level + 1,
CONVERT(varchar(30), f_lineage + '_' + convert(varchar(10), a.f_locationid)),
cast(c.ordering + (CAST(ROW_NUMBER() OVER(ORDER BY a.f_locationname)
as decimal(8,4))/POWER(10,c.f_level + 1)) as decimal(8,4))
FROM cte_locationlineage c
JOIN tb__templocations a
ON a.f_locationparent = c.f_locationID
)
SELECT *
FROM cte_locationlineage c
ORDER BY c.ordering
Run Code Online (Sandbox Code Playgroud)
这样,您就可以结合使用级别和位置名称来对列表中的内容进行排序.
但值得注意的是,如果你的桌子非常大,这可能不实用.ROW_NUMBER()当你遇到越来越大的数据集时会变得相当慢.
编辑:成为一个问题的一件事是,如果你在一个级别中有超过九行,使用上面的例子.您必须增加幅度以反映足够的"空格"来保存信息.例如,每个级别最多可以运行99行:
;WITH cte_locationlineage AS
(
SELECT a.f_locationid, a.f_locationparent, a.f_locationname, 0 AS f_level,
CONVERT(varchar(30), '0_' + convert(varchar(10), f_locationid)) f_lineage,
CAST(ROW_NUMBER() OVER(ORDER BY f_locationname) as decimal(12,8)) as ordering
FROM tb__templocations a
WHERE f_locationparent = '0'
UNION ALL
SELECT a.f_locationid,
a.f_locationparent,
a.f_locationname,
c.f_level + 1,
CONVERT(varchar(30), f_lineage + '_' + convert(varchar(10), a.f_locationid)),
cast(c.ordering + (CAST(ROW_NUMBER() OVER(ORDER BY a.f_locationname) as decimal(12,8))
/POWER(10,(c.f_level + 1)*2)) as decimal(12,8))
FROM cte_locationlineage c
JOIN tb__templocations a
ON a.f_locationparent = c.f_locationID
)
SELECT *
FROM cte_locationlineage c
ORDER BY c.ordering
Run Code Online (Sandbox Code Playgroud)
显然,如果你的每个级别高出999行,这将会变得很麻烦,但我怀疑这不应该是你的意见问题.
我很好奇是否有人有更聪明的方法来使用二进制来完成同样的事情; 我今晚要看看能不算数学.
| 归档时间: |
|
| 查看次数: |
123 次 |
| 最近记录: |