SQL Server: Estrazione risultati query in formato CSV da T-SQL (it-IT)
Introduzione
In alcune occasioni, può essere necessario esportare i risultati provenienti da una query SQL in formato CSV, senza passare per applicativi esterni scritti ad hoc, ma lasciando direttamente a SQL Server l'incombenza di creare e popolare il file. In questo breve how-to vedremo come, abilitando alcune funzionalità di SQL Server, sia possibile sfruttre l'utility bcp direttamente da query, per creare files testuali che espongano il recordset prodotto da un'interrogazione
Operazioni preliminari
Per poter lanciare un eseguibile da query - come bcp -, è anzitutto necessario abilitare in SQL Server la funzione che serve a tale scopo. Infatti, per impostazione predefinita e per sicurezza, tale funzionalità risulta essere disattivata di default. La funzione in questione è xp_cmdshell: essa fa in modo che venga generata una shell di comandi a cui passare il percorso di un dato eseguibile, eventualmente corredato di argomenti.
L'abilitazione di tale funzione si trova tra le opzioni avanzate di SQL Server. Di conseguenza, come prima cosa abiliteremo l'accesso ad esse, per poi flaggare come attiva quella di nostro interesse. Il tutto può essere fatto con il seguente script:
-- Abilitare la modifica delle opzioni avanzate
EXEC sp_configure 'show advanced options', 1;
GO
-- Aggiornamento del valore modificato
RECONFIGURE;
GO
-- Abilitazione della funzionalità specifica (in questo caso, xp_cmdshell)
EXEC sp_configure 'xp_cmdshell', 1;
GO
-- Aggiornamento del valore modificato
RECONFIGURE;
GO
Ora il nostro server SQL è pronto per eseguire shell di sistema. A questo punto possiamo vedere un semplice esempio che - data una certa tabella/recordset - possa esportare i risultati di una query di selezione su file di testo
Esempio
L'utility BCP accetta una tabella come sorgente dati in ingresso. Di conseguenza, supponendo di disporre di una tabella di nome Articoli, procederemo anzitutto a creare una sua copia relativamente ai record di nostro interesse. Questo permetterà di indicare a bcp la tabella contenente i soli record destinati all'esportazione. In più, un approccio di questo tipo permette, tra le altre cose, di andare a creare tabelle risultanti a partire da sintassi anche molto complesse (pensiamo ad una query che coinvolga molte tabelle) che verranno poi eliminate appena terminata l'esportazione.
Il tutto seguirà questo approccio:
SELECT ART.CodArticolo
INTO tmpArticoli
FROM Articoli
-- TO DO: Esportazione tramite BCP
DROP TABLE tmpArticoli
Dunque nella tabella tmpArticoli disporremo dei dati che passeremo a bcp per eseguire l'esportazione. Se la eseguissimo da linea di comando, essa potrebbe assumere una forma simile alla seguente:
bcp <NOME_DATABASE>.dbo.tmpArticoli out C:\tmp\esportazione.csv -S<NOME_SERVER> -T -t; -c
Dove NOME_DATABASE è ovviamente il nome del database su cui si trovano lo schema dbo e quindi la tabella tmpArticoli, e NOME_SERVER è l'istanza dalla quale estrarremo la tabella stessa. Sono poi qui riportati alcuni flag, ovvero:
- out
- -T
- -t
- -c
out permette di indicare il percorso completo del file di esportazione; -T specifica che la connessione a SQL Server avverrà in modalità trusted, quindi senza dover indicare nuovamente le credenziali di login, mentre -t specifica il carattere separatore di campo (si noti che, nella sintassi, lo facciamo qui seguire dal carattere ";": in altri termini, i campi oggetto della query saranno separati in questo caso da punto e virgola. Infine, -c indicare che esporteremo i vari campi come tipo char, ovvero come stringhe testuali.
I flag utilizzabili con bcp sono numerosi, e permettono un ottimo livello di personalizzazione: per una lista completa, si veda il link riportato nella Bibliografia.
Tornando all'esempio, ci è ora sufficiente passare alla procedura xp_cmdshell un comando simile a quello appena visto.
Il nostro script finale diventa pertanto:
SELECT ART.CodArticolo
INTO tmpArticoli
FROM Articoli
DECLARE @command VARCHAR(255) = 'bcp TEST.dbo.tmpArticoli out C:\tmp\ART_' + FORMAT(GETDATE(),'yyyyMMddHHmmss') + '.csv -STEST\ISTANZA -T -t; -c'
EXEC master.dbo.xp_cmdshell @command
DROP TABLE tmpArticoli
Alcuni appunti: si noti il nome database TEST. Ovviamente è necessario sostituirlo con il proprio, così come il flag -S, che indica l'istanza, alla quale abbiamo qui assegnato il valore di TEST\ISTANZA. Rimane invariato il resto dell'istruzione, con la sola eccezione del nome file, qui formato dal prefisso ART_ seguito da un timestamp completo ottenuto dal momento di esecuzione (GETDATE()).
Si tenga inoltre presente che il percorso indicato (nel nostro caso, C:\tmp) è sempre una directory del server: il file verrà generato dunque nella cartella indicata - se esistente - lato motore database.