2010-02-19 2 views
4

Vous vous demandez simplement s'il existe un moyen rapide de compter toutes les valeurs NULL (de toutes les colonnes) dans une table MySQL?Comment compter toutes les valeurs NULL dans une table?

Merci pour votre idée!

+0

Il y a un moyen que vous pouvez atteindre en MySQL exclusivement avec SQL. Le code n'est pas simple. Jetez un oeil à la solution postée par moi. – Pentium10

Répondre

4

Si vous voulez que cela fait exclusivement par MYSQL et sans énumérer toutes les colonnes prennent une regarde cette solution.

Dans cette méthode, vous n'avez pas à gérer le nombre de colonnes de base de données en les codant en dur. Si votre schéma de table sera modifié, cette méthode fonctionnera et ne nécessitera pas de changement de code.

SET @db = 'testing'; -- database 
SET @tb = 'fuzzysearch'; -- table 
SET @x = ''; -- will hold the column names with ASCII method applied to retrieve the number of the first char 
SET @numcolumns = 0; -- will hold the number of columns in the table 

-- figure out how many columns we have 
SELECT count(*) into @numcolumns FROM information_schema.columns where [email protected] and [email protected]; 

-- we have to prepare some query from all columns of the table 
SELECT group_concat(CONCAT('ASCII(',column_name,')') SEPARATOR ",") into @x from information_schema.columns where [email protected] and [email protected]; 
-- after this query we have a variable separated with comma like 
-- ASCII(col1),ASCII(col2),ASCII(col3) 

-- we now generate a query to concat the columns using comma as separator (null values are omitted from concat) 
-- then figgure out how many times the comma is in that substring (this is done by using length(value)-length(replace(value,',','')) 
-- the number returned is how many non null columns we have in that column 
-- then we deduct the number from the known number of columns, calculated previously 
-- the +1 is added because there is no comma for single value 
SET @s = CONCAT('SELECT @numcolumns - (length(CONCAT_WS(\',\',', @x, '))-length(replace(CONCAT_WS(\',\',', @x, '),\',\',\'\')) + 1) FROM ',@db,'.',@tb,';'); 
PREPARE stmt FROM @s; 
EXECUTE stmt; 
-- after this execution we have returned for each row the number of null columns 
-- I will leave to you to add a sum() group call if you want to find the null values for the whole table 
DEALLOCATE PREPARE stmt; 

ASCII est utilisé pour éviter la lecture, concaténer des colonnes très longues pour rien, aussi ASCII nous rend sans danger pour les valeurs où le caractère est une première virgule (,). Comme vous travaillez avec des rapports, vous pouvez trouver cela utile car cela peut être réutilisé pour chaque table si vous mettez dans une méthode.

J'ai essayé de laisser autant de commentaires que possible.

Let fendit sur des morceaux de la manière compacte ci-dessus (sens inverse):

Je voulais finir par avoir une requête comme celui-ci

SELECT totalcolumns - notnullcolumns from table; -- to return null columns for each row 

Alors que le premier est facile à Calculated en exécutant:

SELECT count(*) FROM information_schema.columns where [email protected] and [email protected]; 

La seconde les notnullcolumns est un peu douloureuse. Après un morceau d'examen des fonctions disponibles dans MySQL, nous constatons que CONCAT_WS ne concat valeurs nulles

Il faut donc lancer une requête comme ceci:

SELECT CONCAT_WS(",","First name",NULL,"Last Name"); 
returns: 'First name,Last Name' 

Ce qui est bon, nous prenons débarrasser de l'hypothèse nulle valeurs de l'énumération. Mais comment obtenons-nous le nombre de colonnes effectivement concaténées?

Eh bien, c'est difficile.Nous devons calculer le nombre de virgules + 1 pour obtenir les colonnes réellement concaténées.

Pour cette astuce nous avons utilisé la notation SQL suivante

select length(value)-length(replace(value,',','')) +1 from table 

Ok, donc nous avons maintenant le nombre de colonnes concaténées.

Mais la partie la plus difficile est à venir.

Nous devons énumérer toutes les valeurs de CONCAT_WS().
Nous devons avoir quelque chose comme ceci:

SELECT CONCAT_WS(",",col1,col2,col3,col4,col5); 

C'est là que nous devons prendre l'utilisation des déclarations préparées, comme nous devons nous préparer une requête SQL dynamique des colonnes encore inconnues. Nous ne savons pas combien de colonnes seront dans notre tableau. Pour cela, nous utilisons les données de la table des colonnes information_schema. Nous devons passer le nom de la table, mais aussi le nom de la base de données, car nous pourrions avoir le même nom de table dans des bases de données séparées.

Nous avons besoin d'une requête qui retourne col1, col2, col3, col4, Col5 nous sur la CONCAT_WS "string"

Donc, pour cela, nous courons une requête

SELECT group_concat(column_name SEPARATOR ",") into @x from information_schema.columns where [email protected] and tab[email protected]; 

Une chose à mentionner . Lorsque nous avons utilisé la méthode length() et replace() pour connaître le nombre de colonnes concaténées, nous devons nous assurer que les valeurs ne sont pas séparées par des virgules. Mais prenez également note que nous pouvons avoir des valeurs vraiment longues dans nos cellules de base de données. Pour ces deux trucs, nous utilisons la méthode ASCII ('value'), qui retournera le caractère ASCII du premier caractère, qui ne peut pas être une virgule et retournera une valeur nulle pour les colonnes nulles. Cela étant dit, nous pouvons compacter tout cela dans la solution complète ci-dessus.

+0

+1, bien que ce soit un peu difficile à comprendre et à maintenir – Bozho

+0

J'ai ajouté plus de commentaires et cette méthode n'a pas besoin de maintenance, s'il modifie le schéma de la table, il fonctionnera sans changement de code. Ainsi peut être réutilisé pour d'autres causes. – Pentium10

+0

C'était vraiment long et merveilleux, et j'ai résolu le problème que j'avais. Un nombre sur la performance de cette fonction? Merci! – Nirmal

4

Quelque chose comme

select id 
     , sum (case when col1 is null then 1 else 0 end case) col1 
     , sum (case when col2 is null then 1 else 0 end case) col2 
     , sum (case when col3 is null then 1 else 0 end case) col3 
from contacts 
group by id 
+0

Cela implique de connaître le nombre de colonnes pour cette table, sur une grande table, ce n'est pas productif. Vérifiez ma solution. – Pentium10

+0

@Pentium - ce que vous dites est vrai, il existe des moyens de contourner cela. Pour une requête unique, une simple regex contre la sortie cut'n'pasted d'un DESCRIBE suffirait. Ou la requête pourrait être générée à partir de INFORMATION_SCHEMA. – APC

0

Vous devriez vraiment faire cela en utilisant non seulement SQL, mais la langue qui est à votre disposition:

  1. Obtenir les métadonnées de chaque table - soit en utilisant DESCRIBE table, ou en utilisant une fonctionnalité de métadonnées intégrée dans votre technologie d'accès db

  2. Créer des requêtes du type suivant dans une boucle pour chaque colonne n. (En pseudo-code)

    int nulls = 0; 
    for (String colmnName : columNames) { 
        query = "SELECT COUNT(*) FROM tableName WHERE " + columnName + " IS NULL"; 
        Result result = executeQuery(query); 
        nulls += result.size(); 
    } 
    
+0

Cela va exécuter la requête de sélection pour chaque colonne, qui peut être des centaines sur une grande table. Vous pouvez obtenir les métadonnées de chaque table et l'utiliser dans un SQL pour obtenir les valeurs nulles dans les colonnes, consultez ma solution. – Pentium10

+0

il me semble qu'il fait des statistiques ponctuelles, donc il peut le laisser tourner pendant une journée si nécessaire :) – Bozho

0

Quelque chose comme ça (de COL_COUNT de remplacement selon le cas):

select count(*) * COL_COUNT - count(col1) - count(col2) - ... - count(col_n) from table; 
+0

Cela implique de connaître le nombre de colonnes pour cette table, sur une grande table ce n'est pas productif. Vérifiez ma solution. – Pentium10

Questions connexes