I'm attempting to create a sp that profiles data in a table by retrieving counts for every value in every field. The issue I'm running into is that it builds a profile table by doing a series of unions. My current results look like Result 1 below.
My question is: Is there a select statement I can use to make the results look like Result 2 or possibly a better way for me to build the table instead of using unions?
Result 1
Col1 Col1_cnt Col2 Col2_cnt Col3 Col3_cnt
Family 15 <NULL> <NULL> <NULL> <NULL>
Friend 4 <NULL> <NULL> <NULL> <NULL>
Coworker 3 <NULL> <NULL> <NULL> <NULL>
<NULL> <NULL> <NULL> 23 <NULL> <NULL>
<NULL> <NULL> John 15 <NULL> <NULL>
<NULL> <NULL> Jane 4 <NULL> <NULL>
<NULL> <NULL> <NULL> <NULL> <NULL> 8
<NULL> <NULL> <NULL> <NULL> Work 3
<NULL> <NULL> <NULL> <NULL> School 2
<NULL> <NULL> <NULL> <NULL> Social 1
<NULL> <NULL> <NULL> <NULL> Conf 5
Desired Result 2
Col1 Col1_cnt Col2 Col2_cnt Col3 Col3_cnt
Family 15 <NULL> 23 <NULL> 8
Friend 4 John 15 Work 3
Coworker 3 Jane 4 School 2
<NULL> <NULL> <NULL> <NULL> Social 1
<NULL> <NULL> <NULL> <NULL> Conf 5
Here is the sp I created:
DROP PROCEDURE IF EXISTS my_db.usp_profile_data;
DELIMITER $$
CREATE PROCEDURE my_db.usp_profile_data(IN vdb_name VARCHAR(255), IN vtbl_name VARCHAR(255))
BEGIN
#CREATES TEMP TABLE TO HOUSE SCHEMA DATA
DROP TABLE IF EXISTS my_db.profile_data;
CREATE TEMPORARY TABLE my_db.profile_data
(id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
#ord_position INT,
col_name VARCHAR(255),
col_type VARCHAR(255));
#INSERTS COLUMNS OF DB AND TABLE PASSED EXCLUDING SYS FIELDS
INSERT INTO my_db.profile_data(col_name, col_type)
SELECT COLUMN_NAME,
COLUMN_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_schema = vdb_name
AND table_name = vtbl_name
AND EXTRA <> ('auto_increment')
AND COLUMN_NAME NOT IN('update_dt','credate_dt');
#DROP PROFILE TABLE IF ALREADY EXISTS
DROP TABLE IF EXISTS my_db.profile_data_FIN;
#INITIALIZES LOOP VARIABLE
SELECT COUNT(*)
FROM my_db.profile_data
INTO @vLoop;
#INITIALIZE INCREMENT VARIABLE
SET @vInc =1;
#BEGIN LOOP THROUGH FIELDS
WHILE @vInc <= (@vLoop) DO
#STORES COLUMN NAME AND DATA TYPE TO BE USED IN CREATING THE PROFILE TABLE
SELECT col_name,
col_type
FROM my_db.profile_data
WHERE id = @vInc
INTO @vColName,@vColType;
#IF FIRST PASS CREATE THE TABLE, ELSE ADD COLUMNS
IF (@vInc = 1) THEN
SET @vSQL_Tbl = CONCAT('CREATE TEMPORARY TABLE my_db.profile_data_FIN (',@vColName,' ',@vColType,', cnt_',@vColName,' INT)');
ELSE
SET @vSQL_Tbl = CONCAT('ALTER TABLE my_db.profile_data_FIN ADD COLUMN ',@vColName,' ',@vColType,', ADD COLUMN cnt_',@vColName,' INT');
END IF;
#EXECUTES THE DYNAMIC TABLE STATEMENT
PREPARE stmtTbl FROM @vSQL_Tbl;
EXECUTE stmtTbl;
DEALLOCATE PREPARE stmtTbl;
#CREATES SQL QUERY USED TO POPULATE THE PROFILE TABLE
SET @vSQL = CONCAT('INSERT INTO my_db.profile_data_FIN (', @vColName,', cnt_',@vColName,')', 'SELECT ',@vColName,', COUNT(*) AS cnt_',@vColName,' FROM ',vdb_name ,'.', vtbl_name,' GROUP BY ', @vColName, ' ORDER BY 2 DESC');
#EXECUTES THE POPULATION OF THE PROFILE TABLE
PREPARE stmtQry FROM @vSQL;
EXECUTE stmtQry;
DEALLOCATE PREPARE stmtQry;
#SELECT @vSQL;
SET @vInc =@vInc+1;
END WHILE;
SELECT *
FROM my_db.profile_data_FIN;
END$$
DELIMITER ;