Search code examples
mysqlviewpivot-tableprocedure

Error while creating a view with procedure MySQL


I have a problem when I try to create a view using a procedure. I have to do that because I need to make a pivot in MySQL, converting rows of a table in columns of another. The query works great, but when I put it in the "CREATE VIEW" statement it gives me error.

Here is the query with CREATE view

CREATE VIEW `Untitled` AS 
SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'MAX(IF(formazioni_persone.id_formazione = ',
      formazioni.id,
      ', true, false)) AS "',
      formazioni.titolo,'"'
    )
  ) INTO @sql
FROM formazioni;

SET @sql = CONCAT('SELECT persone.*, ', @sql, ' FROM persone INNER JOIN formazioni_persone ON persone.id = formazioni_persone.id_persona GROUP BY persone.id');

PREPARE stmt1 FROM @sql; 

EXECUTE stmt1; 

DEALLOCATE PREPARE stmt1;

The query without CREATE VIEW Untitled AS works great

The query without CREATE VIEW Untitled AS works great. I already tried to create a TEMP TABLE inside the CREATE VIEW, but nothing. Also tried to use delimiters like that, but nothing

DELIMITER $$ 
CREATE VIEW `Untitled` AS 
SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'MAX(IF(formazioni_persone.id_formazione = ',
      formazioni.id,
      ', true, false)) AS "',
      formazioni.titolo,'"'
    )
  ) INTO @sql
FROM formazioni;

SET @sql = CONCAT('SELECT persone.*, ', @sql, ' FROM persone INNER JOIN formazioni_persone ON persone.id = formazioni_persone.id_persona GROUP BY persone.id');

PREPARE stmt1 FROM @sql; 

EXECUTE stmt1; 

DEALLOCATE PREPARE stmt1;
END $$ 
DELIMITER ;

Error: 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 'SET @sql = NULL' at line 2, Time: 0.082000s


Solution

  • A VIEW is not a procedure. A VIEW is only a single SELECT statement, which must have fixed columns at the time you define the VIEW. You can't make a VIEW that is also a procedure.

    Sorry, if you need a pivot-table, you need to specify the values for each column in the query. You can't make a SELECT query or a VIEW that dynamically adds more columns as it finds potential future values.

    And you can't define a VIEW that runs an arbitrary block of procedure code anyway. That would require a procedure.

    You should just use the solutions that are already shown in questions like MySQL - Rows to Columns

    There are no other shortcuts or workarounds.

    By the way, all SQL databases have this restriction, not just MySQL.


    Re your question:

    I'm looking for a solution that doesn't require manual update of the query

    A pivot-table query must have as many columns in the select-list as the number of columns you want it to return. There is no way to make an SQL query that expands the number of columns dynamically as a result of the data it reads at execute time.

    The only way you can make a single query that returns all the data is to NOT do a pivot-table query, and instead return all the data in rows, not columns.

    SELECT p.*, f.titolo, pf.id_persona IS NOT NULL AS ha_formazioni
    FROM persone AS p 
    CROSS JOIN formazioni AS f
    LEFT OUTER JOIN formazioni_persone AS fp ON fp.id_formazioni AND fp.id_persona = p.id
    

    This will return one row for each formazioni per persone. Then you must write code in your application to loop over all the rows of the reesult, and format the data in columns in the manner you want.