En mi artículo anterior sobre el operador de pivote básico, vimos cómo se puede usar el operador de pivote para convertir filas en columnas, lo que da como resultado tablas dinámicas. Vimos que había tres pasos principales para crear una tabla dinámica. El primer paso fue seleccionar los datos base. El segundo paso fue convertir los datos base en una expresión con valores de tabla, y el paso final involucró la aplicación de un operador de pivote a los datos temporales, lo que dio como resultado la tabla dinámica.
Eche un vistazo al siguiente ejemplo.
USE schooldb SELECT * FROM (SELECT city, total_score FROM student ) AS StudentTable PIVOT( AVG(total_score) FOR city IN ([London],[Liverpool],[Leeds],[Manchester]) ) AS StudentPivotTable
Limitaciones del operador pivote
Sin embargo, existen ciertas limitaciones del operador pivote. Dentro del operador pivote, tenemos que especificar el campo agregado y las columnas en las que queremos pivotar nuestros datos. Finalmente, también tenemos que establecer los valores individuales para los encabezados de columna que queremos crear.
Si ejecutamos el script de la sección anterior, obtendríamos el siguiente resultado:
[identificación de la tabla=35 /]
Los encabezados de las columnas son los valores individuales dentro de la columna de la ciudad. Especificamos estos valores dentro del operador pivote en nuestra consulta.
La parte más tediosa de crear tablas dinámicas es especificar manualmente los valores de los encabezados de las columnas. Esta es la parte que es propensa a la mayoría de los errores, especialmente si los datos en su fuente de datos en línea cambian. No podemos estar seguros de que los valores que especificamos en el operador pivote permanecerán en la base de datos hasta que creemos esta tabla pivote la próxima vez.
Por ejemplo, en nuestro script, especificamos Londres, Liverpool, Leeds y Manchester como valores para los encabezados de nuestra tabla dinámica. Estos valores existían en la columna Ciudad de la tabla de estudiantes. ¿Qué pasa si de alguna manera uno o más de estos valores se eliminan o actualizan? En tales casos, se devolverá nulo.
Un mejor enfoque sería crear una consulta dinámica que devuelva un conjunto completo de valores de la columna desde la que intenta generar su tabla dinámica.
Crear una tabla dinámica dinámica
En esta sección, veremos cómo crear una tabla dinámica dinámica.
Esto significa que no necesitaremos especificar manualmente los valores para la columna desde la que estamos tratando de generar nuestra tabla dinámica. En su lugar, estableceremos estos valores dinámicamente. Para ello, utilizaremos la función “QUOTENAME”.
Como siempre, asegúrese de tener una buena copia de seguridad antes de experimentar con un nuevo código. Consulte este artículo sobre cómo realizar copias de seguridad de bases de datos MS SQL si no está seguro.
Función QUOTENAME
La función "QUOTENAME" da formato a los resultados seleccionados. Antes de explicar el pivote dinámico, vale la pena mirar un ejemplo de trabajo rápido de la función "QUOTENAME".
Echa un vistazo a la siguiente consulta.
USE schooldb SELECT QUOTENAME(city)+ ',' FROM student
De forma predeterminada, la función "QUOTENAME" envuelve los elementos seleccionados entre corchetes. El resultado de la consulta anterior se ve así:
[identificación de la tabla=36 /]
Almacenamiento de nombres de columna en una variable
Aunque hemos encerrado los valores de columna entre corchetes, necesitamos especificar los valores en el operador de pivote en este formato:
“[Leeds],[Liverpool],[Londres],[Manchester]”
Para hacer esto, necesitaremos una variable.
USE schooldb DECLARE @CityNames NVARCHAR(MAX) = '' SELECT @CityNames += QUOTENAME(city)+ ',' FROM ( SELECT DISTINCT city FROM student ) AS CITIES PRINT @CityNames
En la consulta anterior, declaramos una variable "@CityNames" y la inicializamos con una cadena vacía. Luego, usamos una declaración SELECT para seleccionar distintos nombres de ciudades de la columna de la ciudad y almacenarlos iterativamente en la variable "@CityNames". En cada iteración, se agregará un valor distinto en la columna de la ciudad junto con una coma a la variable "@CityNames".
Luego, imprimimos el valor almacenado en esta variable. El resultado de la consulta anterior se verá así:
“[Leeds], [Liverpool], [Londres], [Manchester],”
Si observa la salida, hay una coma después del último valor. No necesitamos eso.
Eliminar una coma final
Para eliminar una coma final, usaremos una función IZQUIERDA que toma una cadena como primer argumento. El segundo argumento es el número de caracteres que devolverá esa cadena a partir del primer carácter. Echa un vistazo a la siguiente consulta:
USE schooldb DECLARE @CityNames NVARCHAR(MAX) = '' SELECT @CityNames += QUOTENAME(city)+ ',' FROM ( SELECT DISTINCT city FROM student ) AS CITIES SET @CityNames = LEFT(@CityNames, LEN(@CityNames)-1) PRINT @CityNames
Aquí presta atención a esta línea del script:
SET @CityNames = LEFT(@CityNames, LEN(@CityNames)-1)
En esta línea del script, usamos la función IZQUIERDA para obtener todos los caracteres del lado izquierdo del valor almacenado en la variable "@CityNames", comenzando desde el primer elemento. En el segundo argumento, usamos la función LEN para calcular la cantidad de elementos de valor almacenados en la función "@CityNames" y, finalmente, le restamos 1. Esto elimina la coma final de la cadena. La salida se verá así:
[Leeds],[Liverpool],[Londres],[Manchester]
Conversión de consulta SQL en cadena
Ahora, con suerte, podemos usar la variable "@CityNames" dentro de nuestro operador pivote de esta manera:
PIVOT( AVG(total_score) FOR city IN ( @CityNames )
Sin embargo, no podemos usar una variable dentro de nuestro operador pivote. El enfoque alternativo es convertir nuestra consulta SQL completa en una cadena. Dentro de esta cadena, engancharemos nuestra variable "@CityNames".
USE schooldb DECLARE @CityNames NVARCHAR(MAX) = '' DECLARE @Query NVARCHAR(MAX) = '' SELECT @CityNames += QUOTENAME(city)+ ',' FROM ( SELECT DISTINCT city FROM student ) AS CITIES SET @CityNames = LEFT(@CityNames, LEN(@CityNames)-1) SET @Query = 'SELECT * FROM (SELECT city, total_score FROM student ) AS StudentTable PIVOT( AVG(total_score) FOR city IN (' + @CityNames +') ) AS StudentPivotTable' PRINT @Query
Aquí declaramos una variable "@Query" y almacenamos nuestra consulta SQL en esta variable. Dentro del operador pivote, concatenamos el valor almacenado dentro de la variable "@CityNames". Para ver cómo queda la consulta ejecutada, hemos impreso el valor de la variable “@Query”. La consulta resultante se verá así en la salida:
SELECT * FROM (SELECT city, total_score FROM student ) AS StudentTable PIVOT( AVG(total_score) FOR city IN ([Leeds],[Liverpool],[London],[Manchester]) ) AS StudentPivotTable
Este es exactamente el tipo de consulta que queremos ejecutar. Sin embargo, esto está en el formato de cadena. El paso final es ejecutar esta consulta SQL almacenada como una cadena de texto. Para ello, utilizaremos Dynamic SQL.
Ejecución de SQL dinámico
Usamos el procedimiento incorporado "sp_executesql" para ejecutar SQL dinámico. Usaremos este procedimiento almacenado para ejecutar la consulta almacenada en la variable @Query. Nuestra consulta final que crea una tabla dinámica dinámica se ve así:
USE schooldb DECLARE @CityNames NVARCHAR(MAX) = '' DECLARE @Query NVARCHAR(MAX) = '' SELECT @CityNames += QUOTENAME(city)+ ',' FROM ( SELECT DISTINCT city FROM student ) AS CITIES SET @CityNames = LEFT(@CityNames, LEN(@CityNames)-1) SET @Query = 'SELECT * FROM (SELECT city, total_score FROM student ) AS StudentTable PIVOT( AVG(total_score) FOR city IN (' + @CityNames +') ) AS StudentPivotTable' EXECUTE sp_executesql @Query
Cuando ejecute la consulta anterior, debería ver el siguiente resultado:
[identificación de la tabla=37 /]
Sin embargo, esta vez, no especificamos manualmente los valores para los encabezados de la tabla dinámica. En cambio, los encabezados se calcularon dinámicamente, lo que resultó en una tabla dinámica dinámica.