2013-10-09 21 views
5

Birkaç sütunun z-skorunu (x - μ/σ) belirlemek için bir SQL sorgusu kullanıyorum. ÖzellikleBirden çok sütunun ilgili z-skorunun hesaplanması

, bir tabloda aşağıdaki gibi vardır: ortalama ve standart sapma göre

my_table 
id col_a col_b col_c 
1  3  6  5 
2  5  3  3 
3  2  2  9 
4  9  8  2 

... ve her satır, her sayının z-skoru seçmek istediğiniz onun sütunu.

Yani sonuç şu şekilde görünecektir:

id col_d  col_e  col_f 
1 -0.4343 1.0203 ... 
2  0.1434 -0.8729 
3 -0.8234 -1.2323 
4  1.889  1.5343 

anda benim kod iki sütun için bir puan hesaplar ve şöyle görünür:

select id, 
    (my_table.col_a - avg(mya.col_a))/stddev(mya.col_a) as col_d, 
    (my_table.col_b - avg(myb.col_b))/stddev(myb.col_b) as col_e, 
from my_table, 
select col_a from my_table)mya, 
select col_b from my_table)myb 
group by id; 

Ancak bu son derece yavaştır. Üç sütun sorgu için dakika bekliyorum.

Bunu gerçekleştirmenin daha iyi bir yolu var mı? Ben postgres kullanıyorum ama herhangi bir genel dil bana yardımcı olacaktır. Teşekkürler!

+0

bazı sorular: 1) Neden kimliğine göre el yordamıyla var? Birincil Anahtar ise o zaman herhangi bir şeyi gruplandırmayacaksınız 2) Oradaki 'col_a'yı seç' nedir? 3) Bu aslında bir yorum. Eğer bir şey gruplandırmıyorsanız, o zaman “avg (value)”, 'value' –

+0

'a eşit olacaktır. 1) ID ile gruplamaya ihtiyacım yok, ancak Postgres," column 'my_table.id "' in GROUP BY cümlesinde görünmesi gerektiğini söylüyordu. ", bu yüzden bir hatadan kaçınmak için şu anda yapıyordu 2) Bu seçimlerin sorguda olması gerekmez, doğru. – dmc7z

cevap

13

gibi

şey böyle pencere işlevleri kullanabilirsiniz:

önceden hesaplanmış avg ve stdev ile
select 
    t.id, 
    (t.col_a - avg(t.col_a) over())/stdev(t.col_a) over() as col_d, 
    (t.col_b - avg(t.col_b) over())/stdev(t.col_b) over() as col_e 
from my_table as t 

veya çapraz katılmak:

select 
    t.id, 
    (t.col_a - tt.col_a_avg)/tt.col_a_stdev as col_d, 
    (t.col_b - tt.col_b_avg)/tt.col_b_stdev as col_e 
from my_table as t 
    cross join (
     select 
      avg(tt.col_a) as col_a_avg, 
      avg(tt.col_b) as col_b_avg, 
      stdev(tt.col_a) as col_a_stdev, 
      stdev(tt.col_b) as col_b_stdev 
     from my_table as tt 
    ) as tt 
+2

Pencere fonksiyonlarına yardımcı olacağını söyler. Tam olarak aradığım şey. Teşekkür ederim! – dmc7z

+0

mükemmel çözüm. Tabloda null değerleriniz var mı? –

+0

@ OğuzCanSertel'in sıfır/sıfır problemi, select deyiminde basit bir "CASE" ifadesinin yeterli olacağıdır. – pimbrouwers

-2

Bir tablo değişkeni ort() ve StdDev() niteliklerini seçerek başlayın ve bunun üzerine aşağıdaki sütunlu bir tablo değişkeni alacağı hesaplamalar

için bu tabloyu kullanırsınız AVG_col_a, stddev_col_a, AVG_col b stddev_col_b ...... bu

DECLARE @Table as table (AVG_col_a, stddev_col_a, AVG_col b, stddev_col_b ......) 
INSERT into @Table 
SELECT AVG(col_A), stddev(col_a), ....... 
FROM myTable 

SELECT (m.col_a-AVG_col_a)/stddev_col_a as col_d, 
     (m.col_b-AVG_col_b)/stddev_col_b as col_e 
FROM myTable m, @Table 
+0

Bu PostgreSQL'de çalışmayacak. –

+0

Daha sonra temp tablosunu kullanabilir, herhangi bir genel dilin @mu'nin – Hedinn

0

fıkra İLE bir kullanma:

WITH stats AS (SELECT avg (col_a) a_avg, stddev (col_a) a_stddev, 
         avg (col_b) b_avg, stddev (col_b) b_stddev 
        FROM my_table 
      ) 
SELECT id, (col_a - a_avg)/a_stddev col_d, 
      (col_b - b_avg)/b_stddev col_e 
    FROM my_table, stats 

Ama Roman'ın pencere çözümü daha çok seviyorum.

Oğuz İçin

: my_table NULL değerlere başa:

WITH stats AS ( 
       SELECT avg (col_a) a_avg, stddev (col_a) as a_stddev, 
        avg (col_b) b_avg, stddev (col_b) as b_stddev 
        FROM my_table 
      ) 
SELECT id, 
     COALESCE ((col_a - a_avg)/a_stddev, NULL) col_d, 
     COALESCE ((col_b - b_avg)/b_stddev, NULL) col_e 
FROM my_table, stats 
İlgili konular