crear columnas creadas dinámicamente a partir de una tabla en mysql

Me gustaría crear columnas virtuales que sean dinámicas donde los valores se generen en función de una tabla de combinación.

tengo la siguiente tabla llamada tipos:

id, name
1, TypeA
2, TypeB

y tengo una tabla llamada categoría

id, name, type
1, a, 1
2, b, 2

Me gustaría tener una consulta que devuelva lo siguiente

category name, TypeA, TypeB
a, 1, 0
b, 0, 1

es esto posible hacer en mysql?

preguntado el 01 de julio de 12 a las 08:07

¿Sabe cuántos tipos (columnas) comprobará de antemano? Si es así, ¿solo desea mostrar un valor booleano? 0 or 1 si ese tipo existe para la categoría? -

2 Respuestas

Resumiría varios casos aquí.

  1. La primera y más sencilla es la siguiente:

    SELECT c.name AS "CatName",
           IF(typea.id IS NULL, 0, 1) AS "TypeA",
           IF(typeb.id IS NULL, 0, 1) AS "TypeB"
      FROM category c
      LEFT JOIN types typea ON c.type = typea.id AND typea.name = 'TypeA'
      LEFT JOIN types typeb ON c.type = typeb.id AND typeb.name = 'TypeB';
    

    Pero esto requiere mencionar manualmente todos los tipos en la consulta, que aparentemente no es lo que está buscando.

  2. Es posible crear una consulta SQL y usarla, este método asume que está ejecutando consultas desde algún script, que puede tomar el resultado de la primera consulta y usarla como una nueva consulta.

    SELECT concat('SELECT c.name AS "CatName",',
        group_concat(concat('IF(',lower(t.name),
          '.id IS NULL,0,1) AS "',t.name,'"')),
        ' FROM category c ',
        group_concat(concat('LEFT JOIN types ',
          lower(t.name),' ON c.type = ',lower(t.name),'.id AND ',
          lower(t.name),'.name = ''',t.name,'''') SEPARATOR ' '),
        ';')
      FROM types t;
    

    Escribir un script de shell pequeño (u otro) debería ser fácil.

  3. En el SQL estándar no es posible utilizar el contenido de las tablas para crear DML declaraciones. Diferentes bases de datos proporcionan diferentes facilidades para esto, como PIVOT declaración, lenguajes de procedimiento, etc. No sé cómo lograr esto con las instalaciones de MySQL, pero la idea es construir dinámicamente una consulta descrita en el punto #2 y ejecutarla.

He cubierto los primeros 2 casos en el Violín SQL.

Respondido el 23 de enero de 16 a las 09:01

Su segunda solución es interesante ya que es como mi ejemplo de PHP que crea dinámicamente la consulta en función de cuántos tipos hay. Me pregunto si algo así podría incorporarse a un procedimiento almacenado. - Zane Bien

@ZaneBien, seguro que es posible. No sé cómo hacerlo en MySQL, pero con PostgreSQL es bastante sencillo para mí. - Vyegorov

Hay una función llamada PIVOT que hace lo que quieres, pero desafortunadamente no está disponible en MySQL.

Lo que tú podría sin embargo, es concatenar todos los tipos en una sola cadena por categoría:

SELECT
    a.name,
    GROUP_CONCAT(b.name) AS types
FROM
    category a
LEFT JOIN
    types b ON a.type = b.id
GROUP BY
    a.id

Lo que resultaría en algo como:

name    |    types
--------------------------------
a       |    TypeA
b       |    TypeB
c       |    TypeA,TypeB,TypeC,TypeD

donde categoría c tiene cuatro tipos diferentes, pero a y b sólo tienen un tipo asociado con ellos.

Si sabes de antemano qué y cuántos typeSi va a verificar y desea mostrar un valor booleano si ese tipo existe para la categoría, puede hacer esto:

SELECT,
    a.name,
    b.id IS NOT NULL AS TypeA,
    c.id IS NOT NULL AS TypeB,
    -- etc...
FROM
    category a
LEFT JOIN
    types b ON a.type = b.id AND b.id = 1
LEFT JOIN
    types c ON a.type = c.id AND c.id = 2
-- etc...

Edit: Si no sabe la cantidad de columnas que va a crear de antemano, pero aún quiere valores booleanos para cada tipo en sus propias columnas separadas, otra opción sería construir dinámicamente la cadena de consulta en la lógica de su aplicación. Digamos que estabas usando PHP, por ejemplo:

$columns = $ljoins = array();
$i = 1;

foreach($pdo->query('SELECT id, name FROM types') as $row)
{
    $columns[] = "t$i.id IS NOT NULL AS " . $row['name'];
    $ljoins[] = "LEFT JOIN types t$i ON a.type = t$i.id AND t$i.id = " . $row['id'];
    $i++;
}

$sql = 'SELECT a.name, ' . implode(', ', $columns) . ' FROM category a ' . implode(' ', $ljoins);
$stmt = $pdo->query($sql);

// Do stuff with result-set

Respondido 01 Jul 12, 09:07

Eso no es lo que estoy buscando. Me gustaría que el tipo se muestre como la columna. entonces, en lugar de "tipos", me gustaría mostrar typea, typeb. Estoy empezando a creer que eso no es posible. - Dani

Sí, PIVOT solo está disponible para DBMS de Oracle y SQL Server. ¿En qué estás desarrollando tu aplicación? Una cosa que realmente podría hacer es construir dinámicamente su consulta en la lógica de su aplicación. Primero, consultaría todos los tipos y sus ID, luego crearía dinámicamente una cadena de consulta utilizando esa información al concatenar muchos LEFT JOINs como hay tipos. De esta manera, no está codificando la selección de columna en su consulta, pero sigue siendo una solución torpe que sería mejor si se manejara en SQL. - Zane Bien

Creo que la solución alternativa a esto es usar group_concat. entonces, para cada categoría, mostraría una columna de tipo separada por comas de la siguiente manera: groupa, type1, type2 - Dani

Primera solución editada para que mostrara los nombres de los tipos en el group_concat cuerda. - Zane Bien

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.