Jeśli chcesz, aby było to wykonywane wyłącznie przez MYSQL i bez wyliczania wszystkich kolumn, spójrz na to rozwiązanie.
W tej metodzie nie musisz utrzymywać liczby kolumn bazy danych przez ich stałe kodowanie. Jeśli schemat tabeli zostanie zmodyfikowany, ta metoda będzie działać i nie będzie wymagać zmiany kodu.
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 służy do unikania czytania, łączenia bardzo długich kolumn bez powodu, również ASCII zapewnia nam bezpieczeństwo dla wartości, w których pierwszym znakiem jest przecinek(,).
Ponieważ pracujesz z raportami, może się to okazać pomocne, ponieważ można je ponownie wykorzystać dla każdej tabeli, jeśli wprowadzisz metodę.
Starałem się umieścić jak najwięcej komentarzy.
Podzielmy na kawałki powyższy zwarty sposób (odwrotny sposób):
Chciałem skończyć z takim zapytaniem
SELECT totalcolumns - notnullcolumns from table; -- to return null columns for each row
Podczas gdy pierwszy z nich można łatwo obliczyć, uruchamiając:
SELECT count(*) FROM information_schema.columns where [email protected] and [email protected];
Drugi z nich to notnullcolumns jest trochę uciążliwy.Po częściowym zbadaniu funkcji dostępnych w MySQL, wykryliśmy, że CONCAT_WS nie ma wartości CONCAT null
Uruchom zapytanie w ten sposób:
SELECT CONCAT_WS(",","First name",NULL,"Last Name");
returns: 'First name,Last Name'
To dobrze, usuwamy wartości null z wyliczenia. Ale jak uzyskać, ile kolumn zostało faktycznie połączonych?
Cóż, to jest trudne. Musimy obliczyć liczbę przecinków+1, aby uzyskać faktycznie połączone kolumny.
Do tej sztuczki użyliśmy następującej notacji SQL
select length(value)-length(replace(value,',','')) +1 from table
Ok, więc mamy teraz liczbę połączonych kolumn.
Ale trudniejsza część nadchodzi.
Musimy wyliczyć dla CONCAT_WS() wszystkie wartości.
Musimy mieć coś takiego:
SELECT CONCAT_WS(",",col1,col2,col3,col4,col5);
W tym miejscu musimy skorzystać z przygotowanych instrukcji, ponieważ musimy dynamicznie przygotować zapytanie SQL z jeszcze nieznanych kolumn. Nie wiemy, ile kolumn będzie w naszej tabeli.
Więc do tego używamy danych z tabeli kolumn information_schema. Musimy przekazać nazwę tabeli, ale także nazwę bazy danych, ponieważ możemy mieć tę samą nazwę tabeli w oddzielnych bazach danych.
Potrzebujemy zapytania, które zwraca nam col1,col2,col3,col4,col5 w „ciągu” CONCAT_WS
W tym celu uruchamiamy zapytanie
SELECT group_concat(column_name SEPARATOR ",") into @x from information_schema.columns where [email protected] and [email protected];
Jeszcze jedna rzecz, o której warto wspomnieć. Kiedy użyliśmy metod length() i replace(), aby dowiedzieć się, ile kolumn zostało połączonych, musimy upewnić się, że między wartościami nie ma przecinków. Pamiętaj jednak, że w komórkach bazy danych możemy mieć naprawdę długie wartości. W obu tych trikach używamy metody ASCII('wartość'), która zwróci znak ASCII pierwszego znaku, który nie może być przecinkiem i zwróci wartość null dla kolumn o wartości null.
Mając to na uwadze, możemy to wszystko skompresować w powyższym kompleksowym rozwiązaniu.