2010-03-15 48 views
5

Tôi có một bảng lớn (của các trang web) với một số cột số - nói a đến f. (Đây là thứ hạng trang web từ các tổ chức khác nhau, như alexa, google, quantcast, v.v. Mỗi loại có một phạm vi và định dạng khác nhau; chúng là các bãi thẳng từ các DB bên ngoài.)mysql: Trung bình trên nhiều cột trong một hàng, bỏ qua null

Đối với nhiều bản ghi, một hoặc nhiều của các cột này là null, bởi vì DB bên ngoài không có dữ liệu cho nó. Tất cả đều bao gồm các tập con khác nhau của DB của tôi.

Tôi muốn cột t là trọng số trung bình (mỗi a..f có trọng số tĩnh mà tôi chỉ định), bỏ qua giá trị null (có thể xuất hiện trong bất kỳ giá trị nào), ngoại trừ null nếu chúng là tất cả .

Tôi muốn thực hiện điều này bằng cách tính toán SQL đơn giản, thay vì thực hiện nó trong mã ứng dụng hoặc sử dụng một số lồng nhau xấu xí nếu chặn để xử lý mọi hoán vị của các giá trị rỗng. (Do tôi có số lượng cột tăng lên trung bình khi tôi thêm vào nhiều nguồn DB bên ngoài hơn, điều này sẽ trở nên tồi tệ hơn và dễ bị lỗi hơn theo cấp số nhân.)

Tôi muốn sử dụng AVG nhưng chỉ dành cho nhóm theo, và đây là w/trong một bản ghi. Dữ liệu là vô nghĩa về mặt ngữ nghĩa và tôi không muốn tính trung bình ở một số giá trị "trung bình" thay cho các giá trị rỗng; Tôi chỉ muốn đếm các cột có dữ liệu ở đó.

Có cách nào tốt để thực hiện việc này không?

Lý tưởng nhất, những gì tôi muốn là một cái gì đó giống như UPDATE sites SET t = AVG(a*@a_weight,b*@b_weight,...) trong đó bất kỳ giá trị null nào chỉ bị bỏ qua và không có nhóm nào đang xảy ra.

EDIT: Những gì tôi đã kết thúc sử dụng, dựa trên van và thêm vào bình quân gia quyền đúng (giả định rằng a đã được bình thường hóa khi cần thiết, trong trường hợp này vào một phao 0-1 (1 = tốt hơn):

UPDATE sites 
SET t = (@a_weight * IFNULL(a, 0) + ...)/(IF(a IS NULL, 0, @a_weight) + ...) 
WHERE (IF(a IS NULL, 0, 1) + ...) > 0 

Trả lời

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) 
      ) 

bạn có thể sử dụng COALESCE còn ở các bộ phận khác, nhưng điều này sẽ không xử lý các trường hợp khi bạn có một đánh giá với giá trị 0 đúng bởi vì nó sẽ được loại trừ. các khoản WHERE tránh DivideByZero, nhưng bạn có thể cần phải có thêm tuyên bố UPDATE để xử lý trường hợp này , nếu không có xếp hạng cho mục nhập.

+0

Tôi nghĩ IFNULL là giải pháp thay thế rõ ràng hơn cho COALESCE, nhưng tương đương. IF (IS NULL, 0,1) đơn giản hơn CASE của bạn. Nếu không, tôi nghĩ rằng điều này làm mọi thứ tôi muốn - về cơ bản bạn đang zeroing các cột null và lấy nó ra khỏi mẫu số, đó là điều thông minh để làm và một cái gì đó tôi nên nghĩ đến. :-P – Sai

Các vấn đề liên quan