2009-06-19 8 views
1

J'ai une table qui contient 32 colonnes dans une table Oracle.Comptage de colonnes non nulles d'une manière plutôt étrange

  • Deux de ces colonnes sont des colonnes d'identité
  • le repos sont des valeurs

Je voudrais obtenir la moyenne de toutes les colonnes de valeur, qui est compliquée par les colonnes null (identité). Ci-dessous le pseudo-code pour ce que je suis en train de réaliser:

SELECT 
      ((nvl(val0, 0) + nvl(val1, 0) + ... nvl(valn, 0)) 
     /nonZero_Column_Count_In_This_Row) 

tel que: nonZero_Column_Count_In_This_Row = (ifNullThenZeroElse1 (val0) + ifNullThenZeroElse1 (val1) ... ifNullThenZeroElse (valn))

La difficulté ici est bien sûr en obtenant 1 pour toute colonne non nulle. Il semble que j'ai besoin d'une fonction similaire à NVL, mais avec une clause else. Quelque chose qui retournera 0 si la valeur est nulle, mais 1 sinon, plutôt que la valeur elle-même.

Comment dois-je procéder pour obtenir la valeur du dénominateur?


PS: Je sens que je dois expliquer une certaine motivation derrière cette conception. Idéalement, cette table aurait été organisée comme les colonnes d'identité et une valeur par ligne avec un identifiant pour la ligne elle-même. Cela l'aurait rendu plus normalisé et la solution à ce problème aurait été assez simple. Les raisons pour lesquelles cela ne doit pas être fait sont le débit et l'économie d'espace. C'est un énorme DB où nous insérons 10 millions de valeurs par minute. Faire chacune de ces valeurs une rangée signifierait 10M lignes par minute, ce qui n'est certainement pas réalisable. En emballant 30 d'entre eux dans une seule rangée, on réduit le nombre de lignes insérées dans quelque chose que l'on peut faire avec un seul DB, et la quantité de données supplémentaires (les données d'identité) beaucoup moins.

Répondre

2

(cas Lorsque col est nul alors 0 1 autre fin)

1

Vous pouvez utiliser NVL2(val0, 1, 0) + NVL2(val1, 1, 0) + ... puisque vous utilisez Oracle.

0

génériquement, vous pouvez faire quelque chose comme ceci:

SELECT (
     (COALESCE(val0, 0) + COALESCE(val1, 0) + ...... COALESCE(valn, 0)) 
    /
     (SIGN(ABS(COALESCE(val0, 0))) + SIGN(ABS(COALESCE(val1, 0))) + ....) 
     ) AS MyAverage 

La ligne supérieure retourne la somme des valeurs (valeurs NULL) en omettant alors que la ligne de fond renvoie le nombre de valeurs non nulles. FYI - c'est la syntaxe de SQL Server, mais COALESCE est comme ISNULL pour la plupart. SIGN renvoie juste -1 pour un nombre négatif, 0 pour zéro et 1 pour un nombre positif. ABS est "valeur absolue".

+1

Salut Aaron, Le seul problème est, cette traite une valeur de zéro et NULL même. En fait, je veux ajouter une valeur de 0 au dénominateur, mais pas la valeur nulle. Merci. –

1

Une autre option est d'utiliser la fonction AVG, qui ignore les valeurs NULL:

SELECT AVG(v) FROM (
WITH q AS (SELECT val0, val1, val2, val3 FROM mytable) 
SELECT val0 AS v FROM q 
UNION ALL SELECT val1 FROM q 
UNION ALL SELECT val2 FROM q 
UNION ALL SELECT val3 FROM q 
); 

Si vous utilisez Oracle11g vous pouvez utiliser la syntaxe UNPIVOT pour le rendre encore plus simple.

+0

Merci beaucoup à tous. Vous êtes absolument génial. Je vais expérimenter toutes ces propositions. Merci encore. –

1

Je vois que c'est une question assez ancienne, mais je ne vois pas une réponse suffisante. J'ai eu un problème similaire, et voici comment je l'ai résolu. Il est assez clair qu'une déclaration de cas est nécessaire.Cette solution est une solution pour les cas où

SELECT COUNT(column) WHERE column {IS | IS NOT} NULL 

ne fonctionne pas pour une raison quelconque, ou, vous devez faire plusieurs

SELECT COUNT (*) 
    FROM A_TABLE 
WHERE COL1 IS NOT NULL; 

SELECT COUNT (*) 
    FROM A_TABLE 
WHERE COL2 IS NOT NULL; 

requêtes mais que vous voulez comme un ensemble de données lorsque vous exécutez le script . Voir ci-dessous; J'utilise ceci pour l'analyse et ça a fonctionné très bien pour moi jusqu'ici.

SUM(CASE NVL(valn, 'X') 
       WHEN 'X' 
       THEN 0 
       ELSE 1 
       END) as COLUMN_NAME 
      FROM YOUR_TABLE; 


Cheers!
Doug

Questions connexes