Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Изглед за идентифициране на групирани стойности или обект

Другият отговор вече е доста дълъг, така че го оставям такъв, какъвто е. Този отговор е много по-добър, по-прост и също така правилен, докато другият има някои крайни случаи, които ще доведат до грешен отговор - ще оставя това упражнение на читателя.

Забележка:За по-голяма яснота са добавени прекъсвания на редовете. Целият блок е една заявка

;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

Първата стъпка е да настроите израз на рекурсивна таблица "ходещ", който ще започне от всяка клетка и ще пътува доколкото може, без да проследява никоя стъпка. Уверяването, че клетките не са преразгледани, се извършва с помощта на посетената колона, която съхранява всяка клетка, която е посетена от всяка начална точка. По-специално, това условие AND W.Visited NOT LIKE '%('+right(P.X,3)+','+right(P.Y,3)+')%' отхвърля клетки, които вече е посетил.

За да разберете как работи останалото, трябва да погледнете резултата, генериран от CTE на "Walker", като изпълните "Select * from Walker order by StartX, StartY" след 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), да се сравни една с друга клетка в същата група и да се намери клетката, в която НЯМА ДРУГА клетка на по-горен ред или ако са на същия ред, е отляво на тази клетка. Това обаче все още ни оставя с твърде много резултати. Помислете само за част от 2 клетки на (3,4) и (4,4):

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 път, което ще ни даде толкова много от клетките в парчето, както можем да получим.

Последната външна заявка просто взема първите редове (RN=1) от всяка подобна (X,Y) група.

За да покажете ВСИЧКИ клетки на всяко парче, променете реда
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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Нулева стойност в параметър varbinary тип данни

  2. Как да получите локализирано име на група администратори на Windows в Inno Setup?

  3. Свързване на SQL Server 2008 с Java:Влизането не бе успешно поради потребителска грешка

  4. Как да експортирате заявка от SQL Server 2005 в CSV

  5. SQL заявка към множество бази данни