I have a value pair table that I want to use to create a member table
Based on Taryns answer to this question
MySQL pivot table query with dynamic columns
I have this code that creates selects the data, which works fine
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(CASE WHEN wpdg_usermeta.meta_key = ''',
meta_key,
''' THEN wpdg_usermeta.meta_value END) `',
meta_key, '`'
)
) INTO #sql
FROM
wpdg_usermeta
WHERE
wpdg_usermeta.meta_key like "member_%"
;
SET #sql = CONCAT('SELECT user_id, ', #sql, '
FROM wpdg_usermeta
GROUP BY user_id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
So, my question is - does anyone know how I could alter this to run an INSERT instead of a SELECT so that I could populate the new member table?
You want to create a new table with the results of the dynamic query. I think the simplest approach is to use the create table ... as select ... syntax.
This requires very few changes to your code, and allow you to create the table on the fly based on the results of the query:
SET #sql = CONCAT(
'CREATE TABLE member AS SELECT user_id, ',
#sql,
' FROM wpdg_usermeta GROUP BY user_id'
);
Note that the datatypes of the new table are inferred from the query's metadata; this might, or might no, to exactly what you want. You can check the documentation for more detaiils.
I recently came across the thread below, and it was very useful in building a dynamic SQL for MySQL.
MySQL pivot row into dynamic number of columns
With that said, I did struggle with trying to debug the statement. Now for the real purpose of this post! To debug, I would run a Select on my variable containing the statement (Select #SQL). Then copy that result from the viewer windows and have the query analyzer review it. Once I did this, development really sped up. I am sure this is known by all the advance pro developers but for any newbies, I hope this help!
My dynamic statement looks like this as a reference.
SET #sql = NULL;
SET ##group_concat_max_len = 50000;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
' sum(
case when symbol = ''',
symbol,
''' then pctttlassets end) AS ',
CONCAT(UPPER(ACode),'_',REPLACE(Symbol, '+', ''))
)
) INTO #sql
from trade_detail this;
SET #sql = CONCAT('SELECT Distinct(main.port_code) as PortCode, ', #sql, '
FROM trade_detail main GROUP BY main.Port_Code');
SELECT #SQL;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
I am attempting to use UF Dashbuilder which adds syntax to my SQL query and I don't know how to correct it.
The call that works is similar to:
call database.report ('1234', 'txt');
Dashbuilder turns it into this which does not work:
SELECT * FROM (call database.report ('1234', 'txt');) AS `dbSQL` LIMIT 1
I could also use the code below from the end of the stored procedure to store the results in a table and then SELECT * FROM TABLE in Dashbuilder, but I don't know how to store the results in a table (dynamic number of columns).
Can you please tell me how I can make a stored procedure work with SELECT * added or how I can store the results from this code in a table?
SET #sql = NULL;
SET SESSION GROUP_CONCAT_MAX_LEN = 1000000; -- default is 1024
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(question = ''', REPLACE(question,"'", "\\'"), ''', answer, NULL)) AS ''', REPLACE(question,"'", "\\'"), ''''
)
) INTO #sql
FROM tmp2;
SET #sql = CONCAT('SELECT id, datestamp, ', #sql, ' FROM tmp2 GROUP BY id');
-- SELECT #sql;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
UPDATE 1.
COMMENTS TO ANSWER 1:
Results from original #SQL:
`SET #sql = CONCAT('SELECT id, datestamp, ', #sql, ' FROM tmp2 GROUP BY id');`
SELECT id, datestamp, MAX(IF(question = '1. Our records show that you got care from the provider named below in the last 6 months. {Provider}. Is that right?', answer, NULL))
AS '1. Our records show that you got care from the provider named below in the last 6 months. {Provider}. Is that right?',
MAX(IF(question = '2. Is this the provider you usually see if you need a check-up, want advice about a health problem, or get sick or hurt?', answer, NULL))
AS '2. Is this the provider you usually see if you need a check-up, want advice about a health problem, or get sick or hurt?',
MAX(IF(question = 'Area', answer, NULL)) AS 'Area',MAX(IF(question = 'Encounter', answer, NULL)) AS 'Encounter' FROM tmp2 GROUP BY id
Results from #SQL:
ERROR: Error Code: 1166. Incorrect column name '1. Our records show that you got care from the provider named below in the last 6 months. {Provider}'
I guess there is a character that it does not like such as the single quotes?
SET #tableName = 'myreport';
SET #sql = CONCAT('CREATE TABLE ', #tableName, ' AS SELECT id, datestamp, ', #sql, ' FROM tmp2 GROUP BY id');
CREATE TABLE myreport AS SELECT id, datestamp, MAX(IF(question = '1. Our records show that you got care from the provider named below in the last 6 months. {Provider}. Is that right?', answer, NULL))
AS '1. Our records show that you got care from the provider named below in the last 6 months. {Provider}. Is that right?',
MAX(IF(question = '2. Is this the provider you usually see if you need a check-up, want advice about a health problem, or get sick or hurt?', answer, NULL))
AS '2. Is this the provider you usually see if you need a check-up, want advice about a health problem, or get sick or hurt?',
MAX(IF(question = 'Area', answer, NULL)) AS 'Area',MAX(IF(question = 'Encounter', answer, NULL)) AS 'Encounter' FROM tmp2 GROUP BY id
UPDATE 2:
THIS WORKS!!! THANKS!
I have to reduce the length of the column name as shown below. Then I can run the stored procedure twice per day and select * from this table in Dashbuilder.
CREATE TABLE myreport AS SELECT id, datestamp, MAX(IF(question = '1. Our records show that you got care from the provider named below in the last 6 months. {Provider}. Is that right?', answer, NULL))
AS '1.',
MAX(IF(question = '2. Is this the provider you usually see if you need a check-up, want advice about a health problem, or get sick or hurt?', answer, NULL))
AS '2.',
MAX(IF(question = 'Area', answer, NULL)) AS 'Area',MAX(IF(question = 'Encounter', answer, NULL)) AS 'Encounter' FROM tmp2 GROUP BY id
UPDATE 3: This works! Thanks!
SET #t = CONCAT('DROP TABLE IF EXISTS ', survey_report );
PREPARE stmt FROM #t;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET #sql = NULL;
SET SESSION GROUP_CONCAT_MAX_LEN = 1000000; -- default is 1024
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(question = ''', REPLACE(question,"'", "\\'"), ''', answer, NULL)) AS ''', REPLACE(udf_clean_column_name(15, udf_remove_tags(question)),"'", "\\'"), ''''
)
) INTO #sql
FROM tmp2;
SET #sql = CONCAT('CREATE TABLE ', survey_report, ' AS SELECT id, datestamp, ipaddr, ', #sql, ' FROM tmp2 GROUP BY id');
-- SELECT #sql;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DROP TEMPORARY TABLE IF EXISTS `survey_lookup`;
DROP TEMPORARY TABLE IF EXISTS `tmp`;
DROP TEMPORARY TABLE IF EXISTS `tmp2`;
Mysql Function to remove spaces, etc. from the column names.
CREATE FUNCTION `udf_clean_column_name`(col_name_len INT, str varchar(200)) RETURNS varchar(200)
BEGIN
SET str = SUBSTRING(str,1,col_name_len);
SET str = TRIM(str);
SET str = Replace(str,' ','_');
SET str = Replace(str,'-','');
SET str = Replace(str,'?','');
SET str = Replace(str,',','');
SET str = Replace(str,'.','');
RETURN str;
END;
Mysql function to remove tags (I don't recall where I got this function).
CREATE FUNCTION `udf_remove_tags`(Dirty varchar(4000))
RETURNS varchar(4000)
DETERMINISTIC
BEGIN
DECLARE iStart, iEnd, iLength int;
WHILE Locate( '<', Dirty ) > 0 And Locate( '>', Dirty, Locate( '<', Dirty )) > 0 DO
BEGIN
SET iStart = Locate( '<', Dirty ), iEnd = Locate( '>', Dirty, Locate('<', Dirty ));
SET iLength = ( iEnd - iStart) + 1;
IF iLength > 0 THEN
BEGIN
SET Dirty = Insert( Dirty, iStart, iLength, '');
set Dirty = Replace(Dirty,' ',''); #No space between & and nbsp;
set Dirty = Replace(Dirty,'\r','');
set Dirty = Replace(Dirty,'\n','');
END;
END IF;
END;
END WHILE;
RETURN Dirty;
END;
I don't see any mention of stored procedures in the UF DashBuilder documentation, so it looks like they don't have a way around this.
You can create a table from a SELECT query. If you omit the column specifications, they'll be derived automatically from the select list of the query.
SET #sql = CONCAT('CREATE TABLE ', tableName, ' AS
SELECT id, datestamp, ', #sql, ' FROM tmp2 GROUP BY id');
PREPARE stmt FROM #sql
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
The Question:
How do I limit the number of columns displayed/produced on a MYSQL pivot table?
My Setup:
I have a table named "updates" that looks like the following:
I have the following snippet of query (This is only part of the query, the whole thing only adds more columns from other tables but this is the only section that gets pivoted):
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(Date = ''',
Date,
''', Description, NULL)) AS ',
CONCAT("'",Date_Format(Date, '%d/%m/%Y'),"'")
)
)INTO #sql
FROM updates;
SET #sql = CONCAT('SELECT Action, ', #sql, ' FROM updates GROUP BY Action');
PREPARE stmt FROM #sql;
EXECUTE stmt;
The result of this query is as follows:
As you can see, this pivots the table as intended with the dates as columns. However, there is potential for these updates (to actions) to become very long before they are "closed" and not displayed. Therefore, I would like to limit the outcome to the latest 3 updates. BUT..Not per action as this would potentially still give me a lot of updates in the pivot table.
I would like to have the most recent 3 dates from the updates table with all updates for each date keeping this pivot format.
Example: The outcome table above would look the same but with the exception of the columns titled "02/10/2016" and "04/10/2016".
Thanks in advance for any assistance or advise.
For anyone else trying to solve this issue, I managed to use the following query to produce the desired results:
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(Date = ''',
Date,
''', Description, NULL)) AS ',
CONCAT("'",Date_Format(Date, '%d/%m/%Y'),"'")
) ORDER BY Date ASC
) INTO #sql
FROM (
SELECT * FROM updates
GROUP BY Date
ORDER BY Date DESC
LIMIT 2)
AS updates;
SET #sql = CONCAT('SELECT Action, ', #sql, ' FROM updates GROUP BY Action');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
I am trying to turn this statement:
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'max(case when year = ',
year,
' then experience_rate end) AS `',
year, '-Pen`'
) ORDER BY year
) INTO #sql
FROM
spooner_pec;
SET #sql = CONCAT('SELECT policy_number, primary_name, ', #sql, '
FROM spooner_pec
GROUP BY policy_number');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Into something like this:
SELECT policy_number, primary_name, (SELECT GROUP_CONCAT(DISTINCT CONCAT('max(case when year = ', year, ' then experience_rate end) AS `', year, '-Pen`') ORDER BY year))
FROM spooner_pec
GROUP BY policy_number
But as you can see by the fiddle, I am getting some strange output as a column instead of the actual columns, what am I doing wrong here?
SQLFiddle
I generally do regular expression search to get all the code in single line or selected code in single line.
Use find & replace
1. Under find section type "\n" --find all next line keywords
2. Under replace section type " " -- replace \n with one blank space
3. Tick "Use Regular Expression"
Your result will be in single line.
Before
After
Replace with section is a blank space
*Note: This approach works on Windows platform and most of the editors.