OVER ile pencere işlevinde DISTINCT kullanma


18

Oracle'dan SQL Server 2014'e bir sorgu geçirmeye çalışıyorum.

İşte Oracle'da harika çalışan sorgum:

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

SQL Server 2014'te bu sorguyu çalıştırmayı denedikten sonra aldığım hata burada.

Use of DISTINCT is not allowed with the OVER clause

Sorunun ne olduğunu bilen var mı? SQL Server'da böyle bir sorgulama mümkün müdür? Tavsiye lütfen.


Aslında her satır için sonuçta bir satıra mı ihtiyacınız var MyTable? Yoksa farklı satırlar yeterli mi? Ve varsa sıfır hata ile bölünmesini dikkate almak gerekmez hiçbir satır içinde MyTable?
Erwin Brandstetter

Yanıtlar:


12

Sorunun ne olduğunu bilen var mı? SQL Server'da böyle bir sorgulama mümkün müdür?

Hayır, şu anda uygulanmadı. Aşağıdaki bağlantı öğesi isteğine bakın.

OVER yan tümcesi geliştirme isteği - Toplama işlevleri için DISTINCT yan tümcesi

Başka bir olası varyant

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) 

dökme NUMERICönlemek tamsayı bölme için vardır. Birleştirme maddesinin nedeni burada açıklanmaktadır .

Bu değiştirilebilir ON M.B = T.B OR (M.B IS NULL AND T.B IS NULL)(ya da sadece tercih edilen bir halinde ON M.B = T.Bise Bsütun null değildir).


14

Bu, B tarafından bölünmüş bir A için ayrı sayımı (*) verir:

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

3
İlginç bir çözüm. Ben Asadece null olmayan ne zaman çalışır bir yasal uyarı olması gerektiğini varsayalım (Ben de nulls sayar düşünüyorum).
ypercubeᵀᴹ

Öyle olmalı abs(dense_rank - dense_rank) + 1inanıyorum.
norcalli

7

Maksimum değerini alabilirsiniz. dense_rank()B tarafından bölümlenmiş A'nın farklı sayısını elde etmek için alabilirsiniz.

A'nın boş değerlere sahip olabileceği durumla ilgilenmek için first_value, bölümde boş bir değer olup olmadığını anlamak için kullanabilirsiniz ve yorumda Martin Smith tarafından önerildiği gibi 1 çıkarı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

Alt sorgu yapmayı, A, B'ye göre gruplandırmayı ve saymayı dahil etmeyi deneyin. Ardından dış sorgunuzda sayınız (farklı) normal bir sayı olur ve sayınız (*) bir toplam (cnt) olur.

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;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.