Zia*_*iad 9 sql sql-server sql-server-2008
作为一个例子,我有5个对象.物体是彼此结合或相邻的红点.换句话说,X + 1或X-1或Y + 1或Y-1.
我需要创建一个MS SQL VIEW,其中包含每个对象的第一个XY坐标,如:
X,Y
=======
1. 1,1
2. 1,8
3. 4,3
4. 5,7
5. 6,5
Run Code Online (Sandbox Code Playgroud)
我无法弄清楚如何在VIEW中对它进行分组(不使用存储过程).任何人都有任何想法会有很大的帮助.谢谢
Ric*_*iwi 11
另一个答案已经很长了,所以我将其保留原样.这个答案更好,更简单,也更正确,而另一个有一些边缘情况会产生错误答案 - 我将把这个练习留给读者.
注意:为清晰起见,添加了换行符.整个块是单个查询
;with Walker(StartX,StartY,X,Y,Visited) as (
select X,Y,X,Y,CAST('('+right(X,3)+','+right(Y,3)+')' as Varchar(Max))
from puzzle
union all
select W.StartX,W.StartY,P.X,P.Y,W.Visited+'('+right(P.X,3)+','+right(P.Y,3)+')'
from Walker W
join Puzzle P on
(W.X=P.X and W.Y=P.Y+1 OR -- these four lines "collect" a cell next to
W.X=P.X and W.Y=P.Y-1 OR -- the current one in any direction
W.X=P.X+1 and W.Y=P.Y OR
W.X=P.X-1 and W.Y=P.Y)
AND W.Visited NOT LIKE '%('+right(P.X,3)+','+right(P.Y,3)+')%'
)
select X, Y, Visited
from
(
select W.X, W.Y, W.Visited, rn=row_number() over (
partition by W.X,W.Y
order by len(W.Visited) desc)
from Walker W
left join Walker Other
on Other.StartX=W.StartX and Other.StartY=W.StartY
and (Other.Y<W.Y or (Other.Y=W.Y and Other.X<W.X))
where Other.X is null
) Z
where rn=1
Run Code Online (Sandbox Code Playgroud)
第一步是设置一个"walker"递归表表达式,该表达式将从每个单元格开始并尽可能地移动而无需回溯任何步骤.确保不重新访问单元格是通过使用被访问列来完成的,该列存储从每个起始点访问过的每个单元格.特别是,这种情况AND W.Visited NOT LIKE '%('+right(P.X,3)+','+right(P.Y,3)+')%'
拒绝它已经访问过的单元格.
要了解其余的工作原理,您需要在CTE之后运行"通过StartX,StartY从Walker订单选择*"来查看"Walker"CTE生成的结果.具有5个细胞的"片段"出现在至少5组中,每组具有不同的(StartX,StartY)
组,但每组具有所有5个(X,Y)
具有不同"访问"路径的片段.
子查询(Z)使用LEFT JOIN + IS NULL将组清除到包含"第一个XY坐标"的每个组中的单个行,由条件定义
Other.StartX=W.StartX and Other.StartY=W.StartY
and (Other.Y<W.Y or (Other.Y=W.Y and Other.X<W.X))
Run Code Online (Sandbox Code Playgroud)
意图是从(StartX,StartY)开始可以访问的每个单元格,以与同一组中的每个其他单元格进行比较,并找到NO OTHER单元格位于更高行的单元格,或者它们是否在同一行,就在这个单元格的左边.然而,这仍然给我们带来了太多结果.在(3,4)和(4,4)处只考虑一个2格的部分:
StartX StartY X Y Visited
3 4 3 4 (3,4) ******
3 4 4 4 (3,4)(4,4)
4 4 4 4 (4,4)
4 4 3 4 (4,4)(3,4) ******
Run Code Online (Sandbox Code Playgroud)
用(3,4)的"第一XY坐标"保留2行,标记为******
.我们只需要一行,所以我们使用Row_Number,因为我们编号,我们也可以选择最长的Visited
路径,这将为我们提供尽可能多的单元格.
最终外部查询仅从每个相似(X,Y)组中获取第一行(RN = 1).
select X, Y, Visited
Run Code Online (Sandbox Code Playgroud)
在中间到
select X, Y, (
select distinct '('+right(StartX,3)+','+right(StartY,3)+')'
from Walker
where X=Z.X and Y=Z.Y
for xml path('')
) PieceCells
Run Code Online (Sandbox Code Playgroud)
哪个给出了这个输出
X Y PieceCells
1 1 (1,1)(2,1)(2,2)(3,2)
3 4 (3,4)(4,4)
5 6 (5,6)
7 5 (7,5)(8,5)(9,5)
8 1 (10,1)(8,1)(8,2)(9,1)(9,2)(9,3)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
365 次 |
最近记录: |