11

Bir tablodaki çeşitli boyutların yüzdelerini hesaplamam gerekir. Paydayı hesaplamak için pencere işlevlerini kullanarak işleri basitleştirmek isterim, ancak bir sorun yaşıyorum çünkü pay bir toplam da olması gerekiyor.Toplu bir yüzdesini hesaplamak için bir SQL pencere işlevi nasıl kullanılır?

Basit bir örnek olarak, aşağıdaki tabloyu almak: Sadece d1 dışına her satırın payını hesaplamak istiyorsanız

create temp table test (d1 text, d2 text, v numeric); 
insert into test values ('a','x',5), ('a','y',5), ('a','y',10), ('b','x',20); 

ardından pencereleme fonksiyonları iyi çalışır:

select d1, d2, v/sum(v) over (partition by d1) 
from test; 

"b";"x";1.00 
"a";"x";0.25 
"a";"y";0.25 
"a";"y";0.50 

Ancak, yapmam gereken şey d1'in d2'si için toplam paylaşımı hesaplamak.

ERROR: column "test.v" must appear in the GROUP BY clause or be used in an aggregate function 

Bunun nedeni olduğunu varsayarak yaşıyorum: şimdi hata olsun, Ancak

select d1, d2, sum(v)/sum(v) over (partition by d1) 
from test 
group by d1, d2; 

:

"b";"x";1.00 
"a";"x";0.25 
"a";"y";0.75 

Yani bu deneyin: Aradığım çıktı şudur Gruplama fonksiyonunda pencere fonksiyonunun muhasebeleştirilmemesinden şikayetçi olmakla birlikte, pencereleme işlevleri zaten gruplama maddesine konamaz.

Bu, Postgresql 8.4'ün bir çatal olan Greenplum 4.1'i kullanıyor ve aynı pencereleme işlevlerini paylaşıyor. Greenplum'un ilişkili alt sorgular yapamayacağını unutmayın.

cevap

16

şudur: Bu bana verir Yani

select d1, d2, sum(p) 
from (
    select d1, d2, v/sum(v) over (partition by d1) as p 
    from test 
) as dt 
group by d1, d2 

: İstenilen sonucu üretir. (012) .( ) .

Pencere işlevleri, toplama işlevlerinden sonra uygulanır. sum(sum(v)) numaralı dış sum(), bu örnekte bir pencere işlevidir ve OVER ... maddesine eklenir, iç sum() ise bir toplamtır.

Efektif olarak aynı şekilde:

WITH x AS (
    SELECT d1, d2, sum(v) AS sv 
    FROM test 
    GROUP BY d1, d2 
    ) 
SELECT d1, d2, sv/sum(sv) OVER (PARTITION BY d1) AS share 
FROM x; 
ya da (CTE olmadan):

SELECT d1, d2, sv/sum(sv) OVER (PARTITION BY d1) AS share 
FROM (
    SELECT d1, d2, sum(v) AS sv 
    FROM test 
    GROUP BY d1, d2 
    ) x; 

ya Mu'nun varyant @. Yan yana: Greenplum, sürüm 4.2 ile ilişkili alt sorguları tanıttı. See release notes.

+0

Ah harika! Ben de peşimdeydim. Mantıklı. Bu şeylerin hepsi bu kadar net değil. – EvilPuppetMaster

+0

@erwinBrandsletter Hayatımı kurtardı! teşekkür ederim – isJustMe

1

Her şeyi pencere işlevleri ile yapmanız mı gerekiyor? Sadece gruba sonucunu gerekir gibi d1 ve d2 tarafından ve daha sonra toplamları toplamı Sesler:

Ben aslında aradığınızı düşünüyorum
d1 | d2 |   sum   
----+----+------------------------ 
a | x | 0.25000000000000000000 
a | y | 0.75000000000000000000 
b | x | 1.00000000000000000000 
+1

Doğru, gerçekten işe yarıyor. Alt sorgusu olmadan yapmak istediğim nedeni, bunun aslında bir BI aracına (Tableau) girmesi ve alt sorguların sorunlara neden olmasıdır. – EvilPuppetMaster

İlgili konular