Si desea que esto lo haga exclusivamente MYSQL y sin enumerar todas las columnas, eche un vistazo a esta solución.
En este método, no tiene que mantener el número de columnas de la base de datos codificándolas. Si se modifica el esquema de su tabla, este método funcionará y no requerirá un cambio de código.
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;
El ASCII se usa para evitar la lectura, concatenando columnas muy largas para nada, también ASCII nos hace seguros para valores donde el primer carácter es una coma (,).
Dado que está trabajando con informes, puede que le resulte útil, ya que se puede reutilizar para cada tabla si introduce un método.
Traté de dejar tantos comentarios como sea posible.
Dividámoslo en pedazos de la forma compacta anterior (forma inversa):
Quería terminar teniendo una consulta como esta
SELECT totalcolumns - notnullcolumns from table; -- to return null columns for each row
Mientras que el primero es fácil de calcular ejecutando:
SELECT count(*) FROM information_schema.columns where [email protected] and [email protected];
El segundo, las columnas notnull, es un poco doloroso. Después de un examen de las funciones disponibles en MySQL, detectamos que CONCAT_WS no CONCAT valores nulos
Así que ejecutar una consulta como esta:
SELECT CONCAT_WS(",","First name",NULL,"Last Name");
returns: 'First name,Last Name'
Esto es bueno, nos deshacemos de los valores nulos de la enumeración. Pero, ¿cómo obtenemos cuántas columnas se concatenaron realmente?
Bueno, eso es complicado. Tenemos que calcular el número de comas+1 para obtener las columnas realmente concatenadas.
Para este truco usamos la siguiente notación SQL
select length(value)-length(replace(value,',','')) +1 from table
Bien, ahora tenemos el número de columnas concatenadas.
Pero la parte más difícil viene después.
Tenemos que enumerar para CONCAT_WS() todos los valores.
Necesitamos tener algo como esto:
SELECT CONCAT_WS(",",col1,col2,col3,col4,col5);
Aquí es donde tenemos que hacer uso de las declaraciones preparadas, ya que tenemos que preparar una consulta SQL de forma dinámica a partir de columnas aún desconocidas. No sabemos cuántas columnas habrá en nuestra tabla.
Así que para esto usamos datos de la tabla de columnas information_schema. Necesitamos pasar el nombre de la tabla, pero también el nombre de la base de datos, ya que podríamos tener el mismo nombre de tabla en bases de datos separadas.
Necesitamos una consulta que nos devuelva col1,col2,col3,col4,col5 en la "cadena" CONCAT_WS
Así que para esto ejecutamos una consulta
SELECT group_concat(column_name SEPARATOR ",") into @x from information_schema.columns where [email protected] and [email protected];
Una cosa más para mencionar. Cuando usamos el método length() y replace() para averiguar cuántas columnas se concatenaron, debemos asegurarnos de no tener comas entre los valores. Pero también tenga en cuenta que podemos tener valores realmente largos en las celdas de nuestra base de datos. Para ambos trucos, usamos el método ASCII('valor'), que devolverá el carácter ASCII del primer carácter, que no puede ser una coma y devolverá un valor nulo para las columnas nulas.
Dicho esto, podemos compactar todo esto en la solución integral anterior.