sql >> Database teknologi >  >> RDS >> Sqlserver

Vis for at identificere grupperede værdier eller objekter

Det andet svar er allerede ret langt, så jeg lader det være som det er. Dette svar er meget bedre, enklere og også korrekt, mens det andet har nogle kant-cases, der vil give et forkert svar - den øvelse skal jeg overlade til læseren.

Bemærk:Linjeskift tilføjes for overskuelighed. Hele blokken er en enkelt forespørgsel

;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
 

Det første trin er at opsætte et "walker" rekursivt tabeludtryk, der starter ved hver celle og rejser så langt det kan uden at gå tilbage til noget trin. At sikre, at celler ikke besøges igen, sker ved at bruge den besøgte kolonne, som gemmer hver celle, der er blevet besøgt fra hvert udgangspunkt. Især denne betingelse AND W.Visited NOT LIKE '%('+right(P.X,3)+','+right(P.Y,3)+')%' afviser celler, som den allerede har besøgt.

For at forstå, hvordan resten fungerer, skal du se på resultatet genereret af "Walker" CTE ved at køre "Select * from Walker order by StartX, StartY" efter CTE. Et "stykke" med 5 celler vises i mindst 5 grupper, hver med en forskellig (StartX,StartY) , men hver gruppe har alle 5 (X,Y) stykker med forskellige "besøgte" stier.

Underforespørgslen (Z) bruger en LEFT JOIN + IS NULL til at luge grupperne ned til den enkelte række i hver gruppe, der indeholder den "første XY-koordinat", defineret af betingelsen

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

Hensigten er, at hver celle, der kan besøges fra (StartX, StartY), skal sammenlignes med hinandens celler i samme gruppe og finde den celle, hvor INGEN ANDEN celle er på en højere række, eller hvis de er på samme række, er til venstre for denne celle. Dette efterlader os dog stadig med for mange resultater. Overvej blot et 2-cellet stykke ved (3,4) og (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 rækker tilbage med den "første XY-koordinat" af (3,4), markeret med ****** . Vi har kun brug for én række, så vi bruger Row_Number, og da vi nummererer, kan vi lige så godt gå efter den længste Visited sti, som ville give os så mange af cellerne i stykket, som vi kan få.

Den sidste ydre forespørgsel tager simpelthen de første rækker (RN=1) fra hver lignende (X,Y) gruppe.

For at vise ALLE cellerne i hver brik skal du ændre linjen
select X, Y, Visited
 

i midten til

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
 

Som giver dette output

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. Kan jeg have flere databaser på oracle express edition

  2. Kan ikke oprette datakilden med mysql

  3. Problemer med at bruge MS Access som front-end til en MySQL-database-backend?

  4. Oprettelse af din egen TinyURL