Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Xem để xác định các giá trị hoặc đối tượng được nhóm

Câu trả lời khác đã khá dài, vì vậy tôi sẽ để nguyên nó. Câu trả lời này tốt hơn, đơn giản hơn và cũng chính xác trong khi câu kia có một số trường hợp phức tạp sẽ tạo ra một câu trả lời sai - Tôi sẽ để bài tập đó cho người đọc.

Lưu ý:Các dấu ngắt dòng được thêm vào để rõ ràng. Toàn bộ khối là một truy vấn duy nhất

;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

Bước đầu tiên là thiết lập một biểu thức bảng đệ quy "walker" sẽ bắt đầu ở mỗi ô và di chuyển xa nhất có thể mà không cần rút lại bất kỳ bước nào. Đảm bảo rằng các ô không được truy cập lại được thực hiện bằng cách sử dụng cột đã truy cập, cột này lưu trữ từng ô đã được truy cập từ mọi điểm bắt đầu. Đặc biệt, điều kiện này AND W.Visited NOT LIKE '%('+right(P.X,3)+','+right(P.Y,3)+')%' từ chối các ô mà nó đã truy cập.

Để hiểu cách hoạt động của phần còn lại, bạn cần xem kết quả được tạo bởi CTE "Walker" bằng cách chạy "Chọn * từ thứ tự Walker theo StartX, StartY" sau CTE. Một "mảnh" có 5 ô xuất hiện trong ít nhất 5 nhóm, mỗi nhóm có một (StartX,StartY) khác nhau , nhưng mỗi nhóm có tất cả 5 (X,Y) các phần có đường dẫn "Đã truy cập" khác nhau.

Truy vấn con (Z) sử dụng LEFT JOIN + IS NULL để xóa các nhóm xuống hàng đơn trong mỗi nhóm có chứa "tọa độ XY đầu tiên", được xác định bởi điều kiện

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

Mục đích là cho mỗi ô có thể được truy cập bắt đầu từ (StartX, StartY), để so sánh với các ô khác trong cùng một nhóm và để tìm ô mà KHÔNG có ô KHÁC nằm trên hàng cao hơn hoặc nếu chúng nằm trên cùng hàng, ở bên trái của ô này. Tuy nhiên, điều này vẫn để lại cho chúng ta quá nhiều kết quả. Chỉ xem xét một mảnh 2 ô tại (3,4) và (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 hàng vẫn có "tọa độ XY đầu tiên" của (3,4), được đánh dấu bằng ****** . Chúng tôi chỉ cần một hàng, vì vậy chúng tôi sử dụng Row_Number và vì chúng tôi đang đánh số, chúng tôi cũng có thể sử dụng Visited dài nhất đường dẫn này sẽ cung cấp cho chúng ta càng nhiều các ô trong mảnh mà chúng ta có thể lấy được.

Truy vấn bên ngoài cuối cùng chỉ cần lấy các hàng đầu tiên (RN =1) từ mỗi nhóm (X, Y) tương tự.

Để hiển thị TẤT CẢ các ô của mỗi phần, hãy thay đổi dòng
select X, Y, Visited

ở giữa đến

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

Cái nào đưa ra kết quả này

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. Tìm hiểu kiểu dữ liệu của các cột được trả về trong tập kết quả trong SQL Server

  2. Bắt buộc người dùng viết mã đầu tiên luôn khởi tạo cơ sở dữ liệu không tồn tại?

  3. Thay đổi chủ sở hữu bảng

  4. Những lầm tưởng về hiệu suất máy chủ SQL có hại, phổ biến

  5. Sử dụng RAND () trong Hàm do Người dùng Xác định