作为示例,我有 5 个对象。对象是绑定(bind)在一起或彼此相邻的红点。换句话说,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
我不知道如何将其分组到VIEW中(不使用存储过程)。任何人有任何想法都会有很大的帮助。 谢谢
最佳答案
另一个答案已经很长了,所以我保持原样。这个答案更好、更简单而且正确,而另一个答案有一些边缘情况会产生错误的答案 - 我将把这个练习留给读者。
注意:为了清晰起见,添加了换行符。整个 block 是一个查询
;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
第一步是设置一个“walker”递归表表达式,该表达式将在每个
细胞并尽可能走得更远,而不走回头路。确保单元格不会被重新访问是通过使用访问列来完成的,该列存储从每个起始点访问过的每个单元格。特别是,此条件 AND W.Visited NOT LIKE '%('+right(P.X,3)+','+right(P.Y,3)+')%'
拒绝它具有的单元格已经访问过。
要了解其余部分的工作原理,您需要通过在 CTE 之后运行“Select * from Walker order by StartX, StartY”来查看“Walker”CTE 生成的结果。具有 5 个单元格的“ block ”至少会出现在 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))
目的是对于从(StartX,StartY)开始访问的每个单元格,与同一组中的其他单元格进行比较,并找到较高行上没有其他单元格的单元格,或者如果它们位于同一行,位于该单元格的左侧。然而,这仍然给我们留下了太多的结果。只考虑 (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) ******
保留 2 行,其“第一个 XY 坐标”为 (3,4),并用 *****
标记。我们只需要一行,因此我们使用 Row_Number,并且由于我们要进行编号,因此我们不妨选择最长的 Visited
路径,这将为我们提供尽可能多的我们能得到的片段内的细胞。
最终的外部查询仅从每个相似的 (X,Y) 组中获取第一行 (RN=1)。
<小时/> 要显示每 block 的所有单元格,请更改行select X, Y, Visited
在中间
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
这给出了这个输出
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)
关于sql - 查看以识别分组值或对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12546369/