Ако искате това да се прави изключително от MYSQL и без да изброявате всички колони, разгледайте това решение.
При този метод не е нужно да поддържате броя на колоните на базата данни, като ги кодирате. Ако схемата на таблицата ви бъде променена, този метод ще работи и няма да изисква промяна на кода.
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 се използва за избягване на четене, свързване на много дълги колони за нищо, също така ASCII ни прави безопасни за стойности, където първият знак е запетая (,).
Тъй като работите с отчети, това може да ви бъде полезно, тъй като може да се използва повторно за всяка таблица, ако въведете метод.
Опитах се да оставя възможно най-много коментари.
Нека да разделим на парчета по горния компактен начин (обратен начин):
Исках да получа запитване като това
SELECT totalcolumns - notnullcolumns from table; -- to return null columns for each row
Докато първото е лесно да се изчисли, като изпълните:
SELECT count(*) FROM information_schema.columns where [email protected] and [email protected];
Вторият notnullcolumns е малко болезнен. След част от преглед на функциите, налични в MySQL, откриваме, че CONCAT_WS не CONCAT null стойности
Така че изпълнявате заявка като тази:
SELECT CONCAT_WS(",","First name",NULL,"Last Name");
returns: 'First name,Last Name'
Това е добре, ние се отърваваме от нулевите стойности от изброяването. Но как да разберем колко колони всъщност са били свързани?
Е, това е трудно. Трябва да изчислим броя запетаи+1, за да получим действително свързаните колони.
За този трик използвахме следната SQL нотация
select length(value)-length(replace(value,',','')) +1 from table
Добре, така че сега имаме броя на свързаните колони.
Но по-трудната част предстои.
Трябва да изброим за CONCAT_WS() всички стойности.
Трябва да имаме нещо подобно:
SELECT CONCAT_WS(",",col1,col2,col3,col4,col5);
Тук трябва да използваме подготвените оператори, тъй като трябва да подготвим динамично SQL заявка от все още неизвестни колони. Не знаем колко колони ще има в нашата таблица.
Така че за това използваме данни от таблицата с колони на information_schema. Трябва да предадем името на таблицата, но също и името на базата данни, тъй като може да имаме едно и също име на таблица в отделни бази данни.
Нуждаем се от заявка, която ни връща col1,col2,col3,col4,col5 на CONCAT_WS "низ"
Така че за това изпълняваме заявка
SELECT group_concat(column_name SEPARATOR ",") into @x from information_schema.columns where [email protected] and [email protected];
Още нещо да спомена. Когато използвахме методите length() и replace(), за да разберем колко колони са били свързани, трябва да се уверим, че нямаме запетаи сред стойностите. Но също така имайте предвид, че можем да имаме наистина дълги стойности в клетките на нашата база данни. И за двата трика използваме метод ASCII('value'), който ще върне ASCII символа на първия знак, който не може да бъде запетая и ще върне null за нулеви колони.
Като се има предвид това, можем да уплътним всичко това в горното цялостно решение.