2016-03-28 11 views
2

Ich bin auf der Suche nach einer eleganten Abfrage, um einen durchschnittlichen Ignorieren von Nullwerten zu erhalten.mysql - Durchschnitt von 2 Feld, Ignorieren Null

Beispiel: Ich habe 2 Werte und ein erwartetes Ergebnis:

SELECT X(10,20) AS result 
-- expected result: 15 

SELECT X(0,20) AS result 
-- expected result: 20 

SELECT X(10,0) AS result 
-- expected result: 10 

SELECT X(0,0) AS result 
-- expected result: NULL 

Dies ist mein Versuch:

(val1+val2)/(2-IF(val1,0,1)-IF(val2,0,1)) 

ein besserer Weg, es zu tun?

danke

+1

Für einen Ausdruck, der nur eingebaute MySQL-Funktionen verwendet, ist das ungefähr so ​​gut wie es wird. Eine kleine Verbesserung: Sie könnten die Werte im Nenner hinzufügen, anstatt sie von 2 zu subtrahieren, z. ** '(val1 + val2)/(IF (val1,1,0) + IF (val2,1,0)) ** – spencer7593

+0

@ spencer7593, das ist eine gute Idee, es kürzer zu machen! – stramin

+0

sehe ich sowieso nicht, um es eleganter zu machen. Meine Präferenz für das 'ABS (SIGN())' -Muster ist wahrscheinlich auf zwei Dinge zurückzuführen: ** 1) ** Behandlung von NULL-Werten. Mit 'ABS (SIGN())' können wir 0, 1 oder NULL zurückbekommen. Mit der IF() -Funktion erhalten wir nur eine 0 oder 1 zurück. (Wählen Sie einfach diejenige aus, die Ihrer Spezifikation am besten entspricht.) Und ** 2) ** ein Überbleibsel aus meiner früheren Zeit ... Oracle didn ' t haben eine glatte IF() Funktion. Meine Tendenz war, mit Ausdrücken und Funktionen (wo praktisch) zu gehen, die in DB2, Teradata und Oracle verfügbar waren. (Und der SIGN-Trick war wirklich praktisch in einem Oracle 'DECODE'.) – spencer7593

Antwort

2

entsprechend Ihrer Anforderung oder MySQL-Version ändern ich es so schreiben würde:

(val1 + val2)/(ABS(SIGN(val1)) + ABS(SIGN(val2))) 

Ich glaube, dass an den OP express gleichwertig ist, die bereits sieht ungefähr so ​​elegant aus wie es wird, ohne eine benutzerdefinierte Funktion zu erstellen.

(Es ist wirklich nur meine persönliche Präferenz die Subtraktion von der Konstante „2“ und die zusätzlichen „1“ und „0“ Konstanten zu vermeiden..)

Wenn ich diesen Ausdruck auf drei Argumente zu verlängern:

(val1 + val2 + val3)/(ABS(SIGN(val1)) + ABS(SIGN(val2)) + ABS(SIGN(val3))) 

NOTES:

die MySQL SIGN Funktion einen ganzzahligen Wert darstellt, das "Zeichen" eines numerischen Wert zurück: -1, 0, 1 oder NULL.

Die MySQL ABS Funktion wird den absoluten Wert einer Zahl zurück, so dass rund um Funktion SIGN Einwickeln, d.h. ABS(SIGN(n)) die Rückkehr 0, 1 oder NULL sein wird. SIGN(ABS(n)) würde das gleiche zurückgeben.

Wenn eines der Argumente NULL ist, gibt dieser Ausdruck NULL zurück. Genau wie der OP Ausdruck.

Ich bin mir nicht sicher, dass das eleganter ist. Aber so würde ich es machen.


Wenn die Absicht ist, die SQL kürzer zu machen, zu spezifizieren val1 und val2 nur einmal, wie sie in den OP Beispielen, die eine Funktion benötigen. Da MySQL dafür keine native Built-Funktion bietet, müssten wir eine benutzerdefinierte Funktion definieren (erstellen).

Aber wenn wir das täten, würden wir die Datentypen der Argumente und den Datentyp der Rückkehr (zB BIGINT, DECIMAL(M,N), DOUBLE, etc.) und wie auch immer wir gehen damit angeben müssen, wird es Potenzial für implizite Datentypkonvertierungen und Rundungen/Ungenauigkeiten.

Ohne eine benutzerdefinierte Funktion müssen val1 und val2 zwei Mal in den Ausdruck einbezogen werden. Aber ich denke, das ist besser als die vier oder fünf Mal in jedem der anderen vorgeschlagenen Ausdrücke.

1

Verwenden CASE die Fälle zu behandeln, wo eine der Säulen 0 speziell ist vor der Mittelung.

SELECT CASE 
     WHEN val1 = 0 AND val2 = 0 THEN NULL 
     WHEN val1 = 0 OR val2 = 0 THEN val1 + val2 
     ELSE (val1+val2)/2 
     END AS avg 
1
select case when val1 = 0 and val2= 0 then null 
       when val1 = 0 and val2 ! = 0 then val2 
       when val1 != 0 and val2= 0 then val1 
       else (val1 + val2) /2 
       end avg 

try