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

đệ quy cte với các chức năng xếp hạng

CHỈNH SỬA

Khi bạn đọc tài liệu CTE liên quan đến đệ quy, bạn sẽ nhận thấy rằng nó có một số giới hạn, chẳng hạn như không thể sử dụng các truy vấn con, theo nhóm, hàng đầu. Tất cả đều liên quan đến nhiều hàng. Từ kiểm tra giới hạn và kiểm tra kế hoạch thực thi, cũng như kiểm tra truy vấn này

with cte as (
  select 1 a, 1 b union all select 1, 2 union all select 1, 3 union all select 2, 4
)
, rcte (a, b, c, d) as (
  select a, b, cast(0 as int), 1 
  from cte
  union all
  select r.a, cte.b, cast(ROW_NUMBER() over (order by r.b) as int), r.d+1
  from rcte r inner join cte on cte.a=r.a
  where r.d < 2
)
select * 
from rcte
where d=2
order by a, b

Tôi chỉ có thể kết luận:

  1. Row_Number () hoạt động trong CTE, khi các bảng khác được kết hợp để tạo ra tập kết quả nhiều hàng
  2. Từ kết quả của việc đánh số, rõ ràng là CTE được xử lý trong một hàng duy nhất thông qua tất cả các lần lặp, từng hàng thay vì nhiều lần, mặc dù nó dường như lặp lại tất cả các hàng đồng thời. Điều này sẽ giải thích lý do tại sao bất kỳ hàm nào áp dụng cho các hoạt động nhiều hàng đều không được phép đối với CTE đệ quy.

Mặc dù tôi dễ dàng đi đến kết luận này, nhưng rõ ràng ai đó đã mất nhiều thời gian hơn để giải thích nó một cách chi tiết chỉ 17 tháng trước ...

Nói cách khác, đây là bản chất của việc SQL Server triển khai CTE đệ quy, vì vậy các hàm cửa sổ sẽ không hoạt động theo cách bạn mong đợi.

Vì lợi ích của người khác, đầu ra là:
a           b           c           d
----------- ----------- ----------- -----------
1           1           1           2
1           2           1           2
2           3           1           2
2           4           1           2

Trong khi bạn đang mong đợi c chứa 1,2,1,2 thay vì 1,1,1,1. Điều này chắc chắn có vẻ như nó có thể là một lỗi, vì không có tài liệu nào nói rằng các hàm cửa sổ sẽ không hoạt động trong phần đệ quy của CTE.

Lưu ý: row_number () trả về bigint, vì vậy bạn có thể chỉ ép neo (c) là bigint.

Vì mỗi lần lặp lại tăng d, bạn có thể thực hiện cửa sổ bên ngoài.

with cte as (
  select 1 a, 1 b union all select 1, 2 union all select 2, 3 union all select 2, 4
)
, rcte (a, b, d) as (
  select a, b, 1 
  from cte
  union all
  select a, b, d+1
  from rcte
  where d < 2
)
select a,b, ROW_NUMBER() over (partition by a,d order by b) c,d
from rcte
--where d=2
order by d, a, b

EDIT - thông tin chi tiết

Trong khi trả lời một câu hỏi khác , Tôi đã chơi thêm một số với CTE đệ quy. Nếu bạn chạy nó mà không có ORDER BY cuối cùng, bạn có thể thấy cách SQL Server tiếp cận đệ quy. Điều thú vị là nó quay ngược lại trong trường hợp này, sau đó thực hiện đệ quy đầu tiên theo chiều sâu đầy đủ trên mỗi hàng.

Bảng mẫu

create table Testdata(SomeID int, OtherID int, Data varchar(max))
insert Testdata select 1, 9, '18,20,22,alpha,beta,gamma,delta'
insert Testdata select 2, 6, ''
insert Testdata select 3, 8, '11,12,.'
insert Testdata select 4, 7, '13,19,20,66,12,232,1232,12312,1312,abc,def'
insert Testdata select 5, 8, '17,19'

Một truy vấn đệ quy

;with tmp(SomeID, OtherID, DataItem, Data) as (
select SomeID, OtherID, LEFT(Data, CHARINDEX(',',Data+',')-1),
    STUFF(Data, 1, CHARINDEX(',',Data+','), '')
from Testdata
union all
select SomeID, OtherID, LEFT(Data, CHARINDEX(',',Data+',')-1),
    STUFF(Data, 1, CHARINDEX(',',Data+','), '')
from tmp
where Data > ''
)
select SomeID, OtherID, DataItem, Data
from tmp
-- order by SomeID

Kết quả hiển thị neo CTE được xử lý trong lần lặp lại một, sau đó là vì lý do gì mỗi hàng trong tập hợp liên kết được đệ quy để hoàn thành (độ sâu đầu tiên) trước khi xử lý các hàng khác.

Tuy nhiên, nó có những công dụng kỳ lạ, như câu trả lời này cho thấy




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Kết nối với Cơ sở dữ liệu MSSQL bằng Flask-SQLAlchemy

  2. SQL Server pivot so với nhiều tham gia

  3. SQL Server 2008 - Thu hẹp Nhật ký Giao dịch - Có cách nào để tự động hóa không?

  4. Chèn hàng loạt danh sách chung C # vào SQL Server

  5. Tách các giá trị được phân tách bằng dấu phẩy trong các cột thành nhiều hàng trong Sql Server