I've written this code for mysql pivot table:
SET #SQL = NULL;
SET ##group_concat_max_len = 6000;
SELECT GROUP_CONCAT( DISTINCT CONCAT( 'MAX(IF(questiondetails = \'', questiondetails, '\', answer, null)) AS \'', questiondetails, '\' ' )) INTO #SQL FROM wtfeedback;
SET #SQL = CONCAT( 'SELECT trialid, productsku, userkey, category, ', #SQL, ' FROM wtfeedback GROUP BY trialid' );
PREPARE stmt FROM #SQL;
EXECUTE stmt;
This works fine in Sequel Pro (mysql gui editor)
But when I paste into my php page to run this code it is showing a syntax error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SET ##group_concat_max_len = 6000;
SELECT GROUP_CONCAT( DISTINCT CONCAT( 'MAX(I' at line 3
I'm struggling to see what the error might be.
Any ideas ? Thanks in advance.
MySQL doesn't use '' to escape single quotes. If you want to embed single quotes in your in-sql strings, then use \':
CONCAT('MAX(IF(questiondetails = \'', questiondetails, '\', answer, null)) AS "', questiondetails, '" ')
^^---------------------^^
From PHP, issue only one statement at a time. I deduce that this is the problem since the error is pointing at the beginning of the second SET.
Here is a stored proc to generate a pivot SELECT for you.
I was struggling with the same issue as Guy Murray, but fought my way out.
Basically I made a stored procedure that lets you run a pivot table on selectable rows and columns, with optional filtering. It does so by first storing the result of a "group by" select query in a temp table, and then fiddling that to a pivot table with the "group_concat" function. Same trick as Guy does.
The advantage is that it goes through the main table only once, which may save time if there are zillions of records in it.
Here is a sample table:
CREATE TABLE `Data` (
`Period` INT(2) NOT NULL,
`Product` VARCHAR(20) NOT NULL DEFAULT '',
`Amount` DOUBLE NOT NULL
) ENGINE=INNODB DEFAULT CHARSET=latin1;
INSERT INTO `Data` (`Period`, `Product`, `Amount`)
VALUES
(1,'PrdA',15484),
(1,'PrdA',45454),
(1,'PrdB',478),
(2,'PrdB',985),
(2,'PrdB',741),
(2,'PrdB',985),
(3,'PrdA',7515),
(3,'PrdA',454),
(3,'PrdB',4584),
(2,'PrdB',445),
(1,'PrdB',669);
And this is the stored procedure. Additional comment in the code.
DELIMITER ;;
CREATE DEFINER=`root`#`localhost` PROCEDURE `pivot`(
source VARCHAR(1000),
val VARCHAR(40),
rws VARCHAR(40),
cls VARCHAR(40),
filter VARCHAR(1000))
BEGIN
/*
Creates a pivot table from any table, view or SQL statement.
Mandatory: source, value, rows, and columns to be pivoted.
Optional filtering.
Sample call strings:
CALL pivot('data', 'amount', 'period', 'product', '');
CALL pivot('(select * from data)', 'amount', 'product', 'period', 'WHERE amount>1000');
*/
/*just to be sure*/
DROP TEMPORARY TABLE IF EXISTS temp1;
/*increase the value of group concat, otherwise the number of columns is very limited*/
SET SESSION group_concat_max_len = 100000;
/*perform a "select...group by" on the source and store it in a temp table1*/
SET #a=CONCAT(
'CREATE TEMPORARY TABLE temp1 (
SELECT ',
rws,' AS rows, ',
cls,' AS cols,
SUM(',val,') AS val
FROM ',source,' S ',
filter, '
GROUP BY '
,rws,', ',
cls,');'
);
PREPARE stmt FROM #a;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
/*use "distinct columns" from temp1 to make a text string #coltext, that contains the column statements, to be used in the final step
Produced text string looks like this: sum(CASE WHEN cols='PrdA' THEN val END) AS 'PrdA', sum(CASE WHEN cols='PrdB' THEN val END) AS 'PrdB' */
SELECT GROUP_CONCAT(
' SUM(CASE WHEN cols=\'',cols,'\' THEN val END) AS \'',cols,'\'')
INTO #coltext
FROM (SELECT DISTINCT(cols) AS cols FROM temp1) A;
/*build the final statement in #b*/
SET #b=CONCAT(
'SELECT
IFNULL(rows, \'Total\') AS ',rws,', '
,#coltext,',
SUM(val) AS Total
FROM temp1
GROUP BY
rows
WITH ROLLUP;');
/*and launch it*/
PREPARE stmt FROM #b;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
/*clean up*/
DROP TEMPORARY TABLE IF EXISTS temp1;
SET #a=NULL;
SET #b=NULL;
SET #coltext=NULL;
END;;
DELIMITER ;
The result looks like this:
period PrdA PrdB total
1 60938 1147 62085
2 NULL 3156 3156
3 7969 4584 12553
total 68907 8887 77794
Hope this shows up correctly on stack overflow. It's my first post here.
edit 2015-10-19: when reading others solutions here, I realised that the code could be cleaned up and improved: it's now free of any hardcoded references. Just plug it in any database and it will work.
Related
SELECT #a:= deger1 FROM iscilik1 WHERE Id=16;
ALTER TABLE iscilik1kisiler MODIFY COLUMN deger4 DECIMAL GENERATED ALWAYS AS (#a*deger3) STORED;
Hi everyone.I have a problem with this code and giving error like this;enter image description here
I could not find where is the problem.Thanks for everything have a good jobs.
SELECT CONCAT( 'ALTER TABLE iscilik1kisiler ',
'MODIFY COLUMN deger4 DECIMAL ',
'GENERATED ALWAYS AS (',
deger1,
'*deger3) STORED' )
INTO #sql
FROM iscilik1
WHERE Id=16;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;
I'm stumped. I want to store either a serialize()'d or json_encode()'d array in MySQL using a stored procedure. This would be to store a user's checked boxes or multiselect options.
We are using stored procedures, and while I like to think I've gotten a good grip on them over the last few months, I'm not sure how to solve the following error:
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'One","Three","Two"]")' at line 1 (SQL: CALL CategoryFieldValues_UpdateAttributeByID("3077", "1", "1234", "field_value", "["One","Three","Two"]"))
Here is my stored procedure:
CREATE PROCEDURE `CategoryFieldValues_UpdateAttributeByID`(
IN siteID INT UNSIGNED,
IN ID INT UNSIGNED,
IN modifiedByID INT UNSIGNED,
IN attribute VARCHAR(255),
IN attrValue VARCHAR(255)
)
BEGIN
SET #d = IHaveAFunctionHere( siteID );
SET #n = 'null';
IF attribute = "category_field_id" THEN SET #n = 0; END IF;
SET #s = CONCAT(
'UPDATE ', #d,'.category_field_values cfv
SET
', attribute, ' = ', QUOTE(NULLIF(attrValue, #n)), ',
modified_by = ', QUOTE(modifiedByID), '
WHERE cfv.id = ', ID, ';' );
PREPARE statement FROM #s;
EXECUTE statement;
SELECT ROW_COUNT() AS ROW_COUNT;
DEALLOCATE PREPARE statement;
END$$
This procedure takes information like the siteID, which it uses to find the right database, and an attrValue that is the value I want to set. It works fine, but now when I need to drop a json_encoded or serialized array at it, it chokes.
The json_encoded array ends up looking like ["One","Three","Two"].
I'm guessing it's bugging out because of unescaped quotes or square brackets, but I'm not totally sure.
Also, I tried a slightly different syntax (below) to no avail:
BEGIN
SET #d = IHaveAFunctionHere( siteID );
SET #n = 'null';
SET #attrValue = attrValue;
IF attribute = "category_field_id" THEN SET #n = 0; END IF;
SET #s = CONCAT(
'UPDATE ', #d,'.category_field_values cfv
SET
', attribute, ' = ?,
modified_by = ', QUOTE(modifiedByID), '
WHERE cfv.id = ', ID, ';' );
PREPARE statement FROM #s;
EXECUTE statement USING #attrValue;
SELECT ROW_COUNT() AS ROW_COUNT;
DEALLOCATE PREPARE statement;
END
I've also tried removing the QUOTEs, and some other small tweaks, and I'm just spent.
I have been trying to change existing table and insert the result into temporary table with memoery engine
1) Step - I swaped rows and columns from existing table
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(`parameterId` = ', `parameterId`, ',`valueId`,NULL)) AS parameter', `parameterId`)
) INTO #sql
FROM product_parameter;
SET #sql = CONCAT('SELECT productId , ', #sql , ' FROM product_parameter GROUP BY productId');
PREPARE stmt FROM #sql;
When I execute the stmt statement it will show me a the result
2) Step - I would like to insert the result to temporary table or for testing into physical table
CREATE TEMPORARY TABLE IF NOT EXISTS temporaryTable ENGINE=MEMORY AS
Is it possible to acomplish my goal by one query? Or should i create table then somehow add the result data?
You should create the temporary table and the populate it.
I have a stored procedure to fetch an id. It concat's the last name with first name as "Stone, Cold" and compares with the _fullname passed which when i var_dump gives
String(13) Stone, Cold
It should give an id
IF NOT ISNULL(_fullname) THEN
SET _fullname = TRIM(_fullname);
SET clause = CONCAT( clause , ' AND CONCAT(c.lname, ', ', c.fname) LIKE CONCAT('%',_fullname,'%')');
END IF;
When i try the same query in MySQL it works perfectly fine but doesn't work in procedure. I'm sure that the problem is syntax in stored procedure.
Try:
DELIMITER //
DROP PROCEDURE IF EXISTS `sp_test`//
CREATE PROCEDURE `sp_test`(IN `_fullname` VARCHAR(20))
BEGIN
DECLARE `clause` VARCHAR(500) DEFAULT '';
IF NOT ISNULL(`_fullname`) THEN
SET `_fullname` := TRIM(`_fullname`);
SET `clause` := CONCAT(`clause`, ' AND CONCAT(`c`.`lname`, '', '', `c`.`fname`) LIKE ''', '%', `_fullname`, '%''');
END IF;
SELECT `clause`;
END//
DELIMITER ;
SQL Fiddle demo
I have a PHP script where users create questionnaires, and the script tables in the DB to store the incoming data. The site's been live for a while, and there are about 100 tables in the database.
My script was awfully flawed! It calls for "tinytext" fields in places where I really need "text". Is there a way to bulk update all of the tinytext columns to text?
Thanks!
Solution without stored procedures (using only phpMyAdmin or any other DBA tool).
Run the following query
SELECT
CONCAT('ALTER TABLE ',
TABLE_NAME,
' CHANGE COLUMN ',
COLUMN_NAME,
' ',
column_name,
' TARGET_TYPE ',
CASE
WHEN IS_NULLABLE = 'NO' THEN ' NOT '
ELSE ''
END,
' NULL;') AS que
FROM
information_schema.columns
WHERE
table_schema = 'MY DB'
AND data_type = 'SOURCE_TYPE';
This query will return you all the statements to fire. You can run them or save into a SQL Upgrade script
Example (from tinyint to bit):
ALTER TABLE mytable CHANGE COLUMN redacted redacted BIT NULL;
ALTER TABLE mytable CHANGE COLUMN redacted2 redacted2 BIT NOT NULL;
One way of doing this, is to find all the tinytext columns in the given database and then create ALTER TABLE statement for the each column. Working solution using stored procedure:
DELIMITER $$
DROP PROCEDURE IF EXISTS `BULK_RETYPE` $$
CREATE PROCEDURE `BULK_RETYPE`(IN SCHEMA_NAME VARCHAR(255), IN FROM_TYPE VARCHAR(255), IN TO_TYPE VARCHAR(255))
BEGIN
DECLARE `done` INT DEFAULT FALSE;
DECLARE tn VARCHAR(255);
DECLARE fn VARCHAR(255);
DECLARE `cur1` CURSOR FOR
SELECT
`TABLE_NAME`,
`COLUMN_NAME`
FROM
`information_schema`.`COLUMNS`
WHERE
`DATA_TYPE` = FROM_TYPE AND `TABLE_SCHEMA` = SCHEMA_NAME;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO `tn`, `fn`;
IF done THEN
LEAVE read_loop;
END IF;
SET #ALTER_SQL = CONCAT('ALTER TABLE ', '`', tn,'`' , ' MODIFY ', '`', fn,'`' , ' ', TO_TYPE);
PREPARE stmt1 FROM #ALTER_SQL;
EXECUTE stmt1;
END LOOP;
CLOSE cur1;
END $$
DELIMITER ;
CALL BULK_RETYPE('test', 'tinytext', 'text');
Not really, though if you use PHPMyAdmin, it's a rather quick task... alternatively, you could export a list of all the tables and fields you need to change and put together the necessary ALTER TABLE statements and then execute them.
You can just select from schema and prepare SQL for mass alter
SELECT table_scheme, table_name, columun_name FROM information_schema.`COLUMNS`
WHERE DATA_TYPE='tinyint'