2010-03-15 11 views
5

Birden fazla sayısal sütuna sahip büyük bir tabloya (siteler) sahibim - a'dan f'ye. (Bunlar, alexa, google, quantcast vb. Gibi farklı kuruluşların site sıralamalarıdır. Her birinin farklı bir aralığı ve biçimi vardır; bunlar dış DB'lerden düz dökümdür.)mysql: Bir satırda birden çok sütun üzerinde ortalama, boş değerleri yok sayıyor

Kayıtların çoğu için, bir veya daha fazla Bu sütunlar boştur, çünkü dış DB'nin verileri yoktur. Hepsi benim DB'imin farklı alt kümelerini kapsar.

Sütunun t ağırlıklı ortalamaları olması (her biri atandığım statik ağırlıklara sahip olmak), boş değerlerin yok sayılması (bunların herhangi birinde gerçekleşebilir), null olmadıkları sürece boş olmaları dışında .

Bunu, basit bir SQL hesaplamasıyla, uygulama kodunda yapmaktan veya boş değerlerin her bir permütasyonunu işlemek için blok halinde çok büyük çirkin bir yuva kullanmaktan ziyade yapmayı tercih ederim. (Daha fazla dış DB kaynağına ekledikçe, ortalama olarak artan bir sütun sayısına sahip olduğum göz önüne alındığında, bu, üstel olarak daha çirkin ve hataya eğilimli olacaktır.)

AVG'yi kullanırdım, ancak bu yalnızca grup tarafından ve bu bir kayıtta w /. Veriler semantik olarak null olabilir ve boş değerlerin yerine bir "ortalama" değerde ortalamak istemiyorum; Sadece verilerin bulunduğu sütunları saymak istiyorum.

Bunu yapmanın iyi bir yolu var mı?

İdeal olarak, istediğim, herhangi bir boş değerin yok sayıldığı ve hiçbir gruplamanın gerçekleşmediği UPDATE sites SET t = AVG(a*@a_weight,b*@b_weight,...) gibi bir şeydir.

DÜZENLEME:

: Ben van en dayanan ve (gerektiğinde a zaten = iyi) bir şamandıra 0-1 (1, bu durumda normalize edildiğini varsayarak doğru ağırlıklı ortalamalar ekleyerek kullanarak sona erdi neler
UPDATE sites 
SET t = (@a_weight * IFNULL(a, 0) + ...)/(IF(a IS NULL, 0, @a_weight) + ...) 
WHERE (IF(a IS NULL, 0, 1) + ...) > 0 

cevap

3
UPDATE sites 
     --// TODO: you might need to round it depending on your type 
SET  t =(COALESCE(a, 0) + 
      COALESCE(b, 0) + 
      COALESCE(c, 0) + 
      COALESCE(d, 0) + 
      COALESCE(e, 0) + 
      COALESCE(f, 0) 
      )/
      ((CASE WHEN a IS NULL THEN 0 ELSE 1 END CASE) + 
      (CASE WHEN b IS NULL THEN 0 ELSE 1 END CASE) + 
      (CASE WHEN c IS NULL THEN 0 ELSE 1 END CASE) + 
      (CASE WHEN d IS NULL THEN 0 ELSE 1 END CASE) + 
      (CASE WHEN e IS NULL THEN 0 ELSE 1 END CASE) + 
      (CASE WHEN f IS NULL THEN 0 ELSE 1 END CASE) 
      ) 
WHERE 0<>((CASE WHEN a IS NULL THEN 0 ELSE 1 END CASE) + 
      (CASE WHEN b IS NULL THEN 0 ELSE 1 END CASE) + 
      (CASE WHEN c IS NULL THEN 0 ELSE 1 END CASE) + 
      (CASE WHEN d IS NULL THEN 0 ELSE 1 END CASE) + 
      (CASE WHEN e IS NULL THEN 0 ELSE 1 END CASE) + 
      (CASE WHEN f IS NULL THEN 0 ELSE 1 END CASE) 
      ) 

diğer bölgelerinde de COALESCE kullanabilirsiniz ama düzgün değeri 0 sahip bir derecelendirme varsa bu durumda idare olmaz hariç bırakılır, çünkü. WHERE fıkra DivideByZero önler, ancak gerekebilir Bu davayı ele almak için ek UPDATE bildirimi var Giriş için puan yoksa.

+0

IFNULL, COALESCE için daha açık bir alternatif olduğunu düşünüyorum, ancak yaklaşık olarak eşdeğerdir. IF (IS NULL, 0,1), CASE'nizden benzer şekilde daha basittir. Aksi takdirde, bence istediğim herşeyi yapar - temelde boş sütunları sıfırlar ve paydayı çıkarırsınız, bu akıllıca bir şey ve düşünmem gereken bir şey. :-P – Sai

İlgili konular