sql - 查看以识别分组值或对象

标签 sql sql-server sql-server-2008

enter image description here

作为示例,我有 5 个对象。对象是绑定(bind)在一起或彼此相邻的红点。换句话说,X+1 或 X-1 或 Y+1 或 Y-1。

enter image description here

我需要创建一个 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/

相关文章:

mysql - 私有(private)聊天系统 - 获取每次聊天的最后一条消息

sql - 在 PIVOT 运算符中分组

sql - 我应该使用 SQL_Variant 数据类型吗?

c# - DISTINCT 关键字不适用于 sql server 中的图像数据类型

sql - 使用 NULL 值更新 Select Join

sql - 从 nodejs 连接 oracle

sql - PostgreSQL 中是否有类似 zip() 函数的东西组合了两个数组?

sql-server - 迁移到 Azure SQL - 如何集成域服务帐户?

SQL Server : From 2008 To 2014 :-The data types datetime and time are incompatible in the add operator. 还有其他解决方案吗?

mysql - SQL查询根据条件返回额外的列