Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Widok, aby zidentyfikować zgrupowane wartości lub obiekt

Druga odpowiedź jest już dość długa, więc zostawiam ją bez zmian. Ta odpowiedź jest o wiele lepsza, prostsza, a także poprawna, podczas gdy druga ma pewne skrajne przypadki, które doprowadzą do błędnej odpowiedzi - pozostawię to ćwiczenie czytelnikowi.

Uwaga:Podziały wierszy są dodawane dla większej przejrzystości. Cały blok to jedno zapytanie

;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

Pierwszym krokiem jest skonfigurowanie rekurencyjnego wyrażenia tabelowego „walker”, które rozpocznie się od każdej komórki i przemieści się tak daleko, jak to możliwe, bez cofania żadnego kroku. Upewnienie się, że komórki nie są ponownie odwiedzane, odbywa się za pomocą kolumny odwiedzonej, która przechowuje każdą odwiedzoną komórkę z każdego punktu początkowego. W szczególności ten warunek AND W.Visited NOT LIKE '%('+right(P.X,3)+','+right(P.Y,3)+')%' odrzuca komórki, które już odwiedził.

Aby zrozumieć, jak działa reszta, musisz spojrzeć na wynik wygenerowany przez „Walker” CTE, uruchamiając „Select * from Walker order by StartX, StartY” po CTE. „Kawałek” z 5 komórkami pojawia się w co najmniej 5 grupach, każda z innym (StartX,StartY) , ale każda grupa ma wszystkie 5 (X,Y) elementy o różnych ścieżkach „Odwiedzonych”.

Podzapytanie (Z) używa LEFT JOIN + IS NULL, aby usunąć grupy do jednego wiersza w każdej grupie, który zawiera „pierwszą współrzędną XY”, określoną przez warunek

     Other.StartX=W.StartX and Other.StartY=W.StartY
        and (Other.Y<W.Y or (Other.Y=W.Y and Other.X<W.X))

Intencją jest, aby każda komórka, którą można odwiedzić, zaczynając od (StartX, StartY), porównać z inną komórką w tej samej grupie i znaleźć komórkę, w której ŻADNA INNA komórka nie znajduje się w wyższym wierszu lub jeśli znajdują się w ten sam wiersz, znajduje się na lewo od tej komórki. To jednak wciąż pozostawia nam zbyt wiele wyników. Rozważ tylko fragment z 2 komórkami w punktach (3,4) i (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)     ******

Pozostały 2 wiersze z "pierwszą współrzędną XY" (3,4), oznaczoną ****** . Potrzebujemy tylko jednego wiersza, więc używamy Row_Number, a ponieważ numerujemy, równie dobrze możemy wybrać najdłuższy Visited ścieżki, która dałaby nam jak najwięcej komórki w kawałku, jak tylko możemy.

Ostatnie zapytanie zewnętrzne po prostu pobiera pierwsze wiersze (RN=1) z każdej podobnej grupy (X,Y).

Aby wyświetlić WSZYSTKIE komórki każdego elementu, zmień linię
select X, Y, Visited

w środku do

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

Które dają ten wynik

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. Dlaczego warto korzystać z typu danych geograficznych SQL Server 2008?

  2. Wiersze do wartości oddzielonych przecinkami za pomocą tagu XML

  3. Jak zmienić ustawienia konfiguracji poczty bazy danych w programie SQL Server (T-SQL)

  4. Dlaczego to zapytanie jest powolne za pierwszym razem po uruchomieniu usługi?

  5. Tworzenie nazw tabel będących zastrzeżonymi słowami/słowami kluczowymi w MS SQL Server