sql >> Base de Datos >  >> RDS >> Database

Crear una tabla dinámica dinámica con la función QUOTENAME

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

Nota: Para crear la base de datos y los datos ficticios, consulte el artículo anterior sobre el Operador pivote.

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.