Database
 sql >> Database >  >> RDS >> Database

Creazione di tabelle pivot dinamiche con la funzione QUOTENAME

Nel mio precedente articolo sull'operatore pivot di base, abbiamo visto come utilizzare l'operatore pivot per convertire le righe in colonne, ottenendo tabelle pivot. Abbiamo visto che c'erano tre passaggi principali per creare una tabella pivot. Il primo passo è stato selezionare i dati di base. Il secondo passaggio consisteva nella conversione dei dati di base in un'espressione con valori di tabella e il passaggio finale prevedeva l'applicazione di un operatore pivot ai dati temporanei, che risultava nella tabella pivot.

Dai un'occhiata all'esempio qui sotto.

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: Per creare il database ei dati fittizi, vedere l'articolo precedente sull'operatore pivot.

Limitazioni dell'operatore pivot

Tuttavia, ci sono alcune limitazioni dell'operatore pivot. All'interno dell'operatore pivot, dobbiamo specificare il campo aggregato e le colonne su cui vogliamo trasformare i nostri dati. Infine, dobbiamo anche impostare i singoli valori per le intestazioni di colonna che vogliamo creare.

Se eseguissimo lo script della sezione precedente, otterremmo il seguente risultato:

[id tabella=35 /]

Le intestazioni delle colonne sono i singoli valori all'interno della colonna della città. Abbiamo specificato questi valori all'interno dell'operatore pivot nella nostra query.

La parte più noiosa della creazione di tabelle pivot è specificare manualmente i valori per le intestazioni di colonna. Questa è la parte che è soggetta alla maggior parte degli errori, in particolare se i dati nell'origine dati online cambiano. Non possiamo essere sicuri che i valori che abbiamo specificato nell'operatore pivot rimarranno nel database fino a quando non creeremo questa tabella pivot la prossima volta.

Ad esempio, nel nostro script, abbiamo specificato Londra, Liverpool, Leeds e Manchester come valori per le intestazioni della nostra tabella pivot. Questi valori esistevano nella colonna Сity della tabella studente. Cosa succede se in qualche modo uno o più di questi valori vengono eliminati o aggiornati? In tali casi, verrà restituito null.

Un approccio migliore sarebbe creare una query dinamica che restituirà un set completo di valori dalla colonna da cui stai tentando di generare la tabella pivot.

Creazione di una tabella pivot dinamica

In questa sezione vedremo come creare una tabella pivot dinamica.

Ciò significa che non avremo bisogno di specificare manualmente i valori per la colonna da cui stiamo cercando di generare la nostra tabella pivot. Invece, imposteremo questi valori in modo dinamico. A tale scopo utilizzeremo la funzione “QUOTENAME”.

Come sempre, assicurati di aver eseguito correttamente il backup prima di sperimentare un nuovo codice. Se non sei sicuro, consulta questo articolo sul backup dei database MS SQL.

Funzione QUOTENAME

La funzione “QUOTENAME” formatta i risultati selezionati. Prima di spiegare il pivot dinamico vale la pena guardare un rapido esempio di funzionamento della funzione “QUOTENAME”.

Dai un'occhiata alla seguente query.

USE schooldb

SELECT QUOTENAME(city)+ ','
FROM student

Per impostazione predefinita, la funzione "QUOTENAME" racchiude gli elementi selezionati tra parentesi quadre. L'output della query precedente è simile al seguente:

[id tabella=36 /]

Memorizzazione dei nomi delle colonne in una variabile

Sebbene abbiamo racchiuso i valori delle colonne tra parentesi quadre, dobbiamo specificare i valori nell'operatore pivot in questo formato:

“[Leeds],[Liverpool],[Londra],[Manchester]”

Per fare ciò, avremo bisogno di una variabile.

USE schooldb

DECLARE @CityNames NVARCHAR(MAX) = ''

SELECT  @CityNames +=   QUOTENAME(city)+ ','
FROM 
(
	SELECT DISTINCT city
	FROM student
) AS CITIES

PRINT @CityNames

Nella query precedente, abbiamo dichiarato una variabile "@CityNames" e l'abbiamo inizializzata con una stringa vuota. Quindi, abbiamo utilizzato un'istruzione SELECT per selezionare nomi di città distinti dalla colonna della città e archiviarli in modo iterativo nella variabile "@CityNames". In ogni iterazione, alla variabile "@CityNames" verrà aggiunto un valore distinto nella colonna della città insieme a una virgola.

Quindi, abbiamo stampato il valore memorizzato in questa variabile. Il risultato della query precedente sarà simile al seguente:

“[Leeds],[Liverpool],[Londra],[Manchester],”

Se guardi l'output, c'è una virgola dopo l'ultimo valore. Non ne abbiamo bisogno.

Rimozione di una virgola finale

Per rimuovere una virgola finale, utilizzeremo una funzione LEFT che accetta una stringa come primo argomento. Il secondo argomento è il numero di caratteri da restituire da quella stringa a partire dal primo carattere. Dai un'occhiata alla seguente query:

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

Presta attenzione a questa riga dello script:

SET @CityNames = LEFT(@CityNames, LEN(@CityNames)-1)

In questa riga dello script, abbiamo utilizzato la funzione LEFT per ottenere tutti i caratteri sul lato sinistro del valore memorizzato nella variabile “@CityNames”, partendo dal primo elemento. Nel secondo argomento, abbiamo utilizzato la funzione LEN per calcolare il numero di elementi di valore memorizzati nella funzione "@CityNames" e, infine, abbiamo sottratto 1 da essa. Questo rimuove la virgola finale dalla stringa. L'output sarà simile a questo:

[Leeds],[Liverpool],[Londra],[Manchester]

Conversione di query SQL in stringa

Ora, si spera, possiamo usare la variabile "@CityNames" all'interno del nostro operatore pivot in questo modo:

PIVOT(
	AVG(total_score)
	FOR city IN ( @CityNames )

Tuttavia, non possiamo utilizzare una variabile all'interno del nostro operatore pivot. L'approccio alternativo consiste nel convertire la nostra query SQL completa in una stringa. All'interno di questa stringa, collegheremo la nostra variabile "@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

Qui abbiamo dichiarato una variabile "@Query" e archiviato la nostra query SQL in questa variabile. All'interno dell'operatore pivot, abbiamo concatenato il valore memorizzato all'interno della variabile "@CityNames". Per vedere come appare la query eseguita, abbiamo stampato il valore della variabile "@Query". La query risultante sarà simile alla seguente nell'output:

SELECT * FROM

(SELECT 
	city,
	total_score
FROM 
	student
)
AS StudentTable
PIVOT(
	AVG(total_score)
	FOR city IN ([Leeds],[Liverpool],[London],[Manchester])
) AS StudentPivotTable

Questo è esattamente il tipo di query che vogliamo eseguire. Tuttavia, questo è nel formato String. Il passaggio finale consiste nell'eseguire questa query SQL archiviata come stringa di testo. Per fare ciò, utilizzeremo Dynamic SQL.

Esecuzione di SQL dinamico

Usiamo la procedura integrata “sp_executesql” per eseguire SQL dinamico. Utilizzeremo questa procedura memorizzata per eseguire la query memorizzata nella variabile @Query. La nostra query finale che crea una tabella pivot dinamica è simile alla seguente:

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

Quando esegui la query precedente, dovresti vedere il seguente risultato:

[id tabella=37 /]

Tuttavia, questa volta, non abbiamo specificato manualmente i valori per le intestazioni della tabella pivot. Invece, le intestazioni sono state calcolate dinamicamente risultando in una tabella pivot dinamica.