Sử dụng DISTINCT trong chức năng cửa sổ với HƠN


18

Tôi đang cố gắng di chuyển một truy vấn từ Oracle sang SQL Server 2014.

Đây là truy vấn của tôi hoạt động rất tốt trong Oracle:

select
count(distinct A) over (partition by B) / count(*) over() as A_B
from MyTable 

Đây là lỗi tôi gặp phải sau khi thử chạy truy vấn này trong SQL Server 2014.

Use of DISTINCT is not allowed with the OVER clause

Bất cứ ai biết vấn đề là gì? Là loại truy vấn có thể có trong SQL Server? Xin tư vấn.


Bạn có thực sự cần một hàng trong kết quả cho mỗi hàng MyTablekhông? Hoặc là các hàng riêng biệt đủ? Và bạn không cần phải xem xét phân chia theo sai số 0 nếu không có hàng trong MyTable?
Erwin Brandstetter

Câu trả lời:


12

Bất cứ ai biết vấn đề là gì? Là loại truy vấn có thể có trong SQL Server?

Không, hiện tại nó không được thực hiện. Xem các yêu cầu mục kết nối sau đây.

Yêu cầu nâng cao mệnh đề OVER - Mệnh đề DISTINCT cho các hàm tổng hợp

Một biến thể khác có thể là

SELECT M.A,
       M.B,
       T.A_B
FROM   MyTable M
       JOIN (SELECT CAST(COUNT(DISTINCT A) AS NUMERIC(18,8)) / SUM(COUNT(*)) OVER() AS A_B,
                    B
             FROM   MyTable
             GROUP  BY B) T
         ON EXISTS (SELECT M.B INTERSECT SELECT T.B) 

các diễn viên đến NUMERICđó để tránh phân chia số nguyên. Lý do cho điều khoản tham gia được giải thích ở đây .

Nó có thể được thay thế bằng ON M.B = T.B OR (M.B IS NULL AND T.B IS NULL)if ưa thích (hoặc đơn giản là ON M.B = T.Bnếu Bcột không thể rỗng).


14

Điều này đưa ra số đếm riêng biệt (*) cho A được phân vùng bởi B:

dense_rank() over (partition by B order by A) 
+ dense_rank() over (partition by B order by A desc) 
- 1

3
Giải pháp thú vị. Tôi cho rằng nó nên có một tuyên bố từ chối trách nhiệm rằng nó hoạt động khi Akhông phải là nullable (vì tôi nghĩ nó cũng tính null).
ypercubeᵀᴹ

abs(dense_rank - dense_rank) + 1Tôi nên tin điều đó.
norcalli

7

Bạn có thể lấy giá trị tối đa của dense_rank()để lấy số lượng riêng biệt của A được phân vùng bởi B.

Để xử lý trường hợp A có thể có các giá trị null, bạn có thể sử dụng first_valueđể tìm hiểu xem null có xuất hiện trong phân vùng hay không và sau đó trừ đi 1 nếu nó được đề xuất bởi Martin Smith trong bình luận.

select (max(T.DenseRankA) over(partition by T.B) - 
          cast(iif(T.FirstA is null, 1, 0) as numeric(18, 8))) / T.TotalCount as A_B
from (
     select dense_rank() over(partition by T.B order by T.A) DenseRankA,
            first_value(T.A) over(partition by T.B order by T.A) as FirstA,
            count(*) over() as TotalCount,
            T.A,
            T.B
     from MyTable as T
     ) as T

5

Hãy thử thực hiện một truy vấn con, nhóm theo A, B và bao gồm cả số đếm. Sau đó, trong truy vấn bên ngoài của bạn, số đếm của bạn (riêng biệt) trở thành một số đếm thông thường và số đếm của bạn (*) trở thành một tổng (cnt).

select
count(A) over (partition by B) * 1.0 / 
    sum(cnt) over() as A_B
from
(select A, B, count(*) as cnt
 from MyTable
 group by A, B) as partial;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.