作为一个例子,我有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
我无法弄清楚如何在 VIEW (不使用存储过程)中对其进行分组。任何人都有任何想法会有很大的帮助。 感谢
答案 0 :(得分: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
第一步是设置一个“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))
意图是从(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) ******
使用{3,4}的“第一个XY坐标”保留2行,标有******
。我们只需要一行,所以我们使用Row_Number,因为我们编号,我们也可以选择最长的Visited
路径,这会给我们多个中的单元格。我们可以得到一块。
最终的外部查询只是从每个相似的(X,Y)组中获取第一行(RN = 1)。
<小时/> 要显示每个部分的所有单元格,请更改行
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)
答案 1 :(得分:0)
假设您的坐标以X,Y形式存储,如下所示:
CREATE Table Puzzle(
id int identity, Y int, X int)
INSERT INTO Puzzle VALUES
(1,1),(1,2),(1,8),(1,9),(1,10),
(2,2),(2,3),(2,8),(2,9),
(3,9),
(4,3),(4,4),
(5,7),(5,8),(5,9),
(6,5)
然后,此查询将以棋盘形式显示您的Puzzle(在SQL Management Studio中以TEXT模式运行)
SELECT (
SELECT (
SELECT CASE WHEN EXISTS (SELECT *
FROM Puzzle T
WHERE T.X=X.X and T.Y=Y.Y)
THEN 'X' ELSE '.' END
FROM (values(0),(1),(2),(3),(4),(5),
(6),(7),(8),(9),(10),(11)) X(X)
ORDER BY X.X
FOR XML PATH('')) + Char(13) + Char(10)
FROM (values(0),(1),(2),(3),(4),(5),(6),(7)) Y(Y)
ORDER BY Y.Y
FOR XML PATH(''), ROOT('a'), TYPE
).value('(/a)[1]','varchar(max)')
它给你这个
............
.XX.....XXX.
..XX....XX..
.........X..
...XX.......
.......XXX..
.....X......
............
如果您将TopLeft单元格定义为TopMost行的最左侧单元格,则分4个阶段完成的查询将为您提供TopLeft单元格的结果。
-- the first table expression joins cells together on the Y-axis
;WITH FlattenOnY(Y,XLeft,XRight) AS (
-- start with all pieces
select Y,X,X
from puzzle
UNION ALL
-- keep connecting rightwards from each cell as far as possible
select B.Y,A.XLeft,B.X
from FlattenOnY A
join puzzle B on A.Y=B.Y and A.XRight+1=B.X
)
-- the second table expression flattens the results from the first, so that
-- it represents ALL the start-end blocks on each row of the Y-axis
,YPieces(Y,XLeft,XRight) as (
--
select Y,XLeft,Max(XRight)
from(
select Y,Min(XLeft)XLeft,XRight
from FlattenOnY
group by XRight,Y)Z
group by XLeft,Y
)
-- here, select * from YPieces will return the "blocks" such as
-- Row 1: 1-2 & 8-10
-- Row 2: 2-3 (equals Y,XLeft,XRight of 2,2,3)
-- etc
-- the third expression repeats the first, except it now combines on the X-axis
,FlattenOnX(Y,XLeft,CurPieceXLeft,CurPieceXRight,CurPieceY) AS (
-- start with all pieces
select Y,XLeft,XLeft,XRight,Y
from YPieces
UNION ALL
-- keep connecting rightwards from each cell as far as possible
select A.Y,A.XLeft,B.XLeft,B.XRight,B.Y
from FlattenOnX A
join YPieces B on A.CurPieceY+1=B.Y and A.CurPieceXRight>=B.XLeft and B.XRight>=A.CurPieceXLeft
)
-- and again we repeat the 2nd expression as the 4th, for the final pieces
select Y,XLeft X
from (
select *, rn2=row_number() over (
partition by Y,XLeft
order by CurPieceY desc)
from (
select *, rn=row_number() over (
partition by CurPieceXLeft, CurPieceXRight, CurPieceY
order by Y)
from flattenOnX
) Z1
where rn=1) Z2
where rn2=1
结果是
Y X
----------- -----------
1 1
1 8
4 3
5 7
6 5
或者你的平面形式是这样的吗?如果是的话,给我们一个喊叫,我会重做解决方案
create table Puzzle (
row int,
[0] bit, [1] bit, [2] bit, [3] bit, [4] bit, [5] bit,
[6] bit, [7] bit, [8] bit, [9] bit, [10] bit, [11] bit
)
insert Puzzle values
(0,0,0,0,0,0,0,0,0,0,0,0,0),
(1,0,1,1,0,0,0,0,0,1,1,1,0),
(2,0,0,1,1,0,0,0,0,1,1,0,0),
(3,0,0,0,0,0,0,0,0,0,1,0,0),
(4,0,0,0,1,1,0,0,0,0,0,0,0),
(5,0,0,0,0,0,0,0,1,1,1,0,0),
(6,0,0,0,0,0,1,0,0,0,0,0,0),
(7,0,0,0,0,0,0,0,0,0,0,0,0)