The only thing that occurs to me that you can try to do from an SP only with TSQL is to take advantage of access to the Ole Automation Procedures
(provided that the server has configured that possibility) and instantiate a Scripting.FileSystemObject
object to take advantage of the% function WriteLine
.
In the first place, it would be necessary to verify and eventually reconfigure the server to allow this type of procedure:
-- Para ver la configuración (1=On)
EXEC sp_configure 'Ole Automation Procedures';
-- Si nos devuelve un error es por que no está habilitado el acceso a las
-- configuraciones avanzadas. Para habilitarlo:
EXEC sp_configure 'show advanced options', 0;
RECONFIGURE;
-- Para configurar los Ole Automation Procedures
EXEC sp_configure 'Ole Automation Procedures', 1;
Having correctly configured the server, the following is a conceptual example of the solution: we want to export the result of a simple query: SELECT id,name FROM SYSOBJECTS
to a file, what we will do is:
- Use a cursor that points to a query
- The query will return a single column that will correspond to each line of the file, you have to convert the missing data to
VARCHAR
and format everything as we want it to go to the file.
- We move the cursor and invoke the
WriteLine
method to write each line
.
DECLARE @FS int
DECLARE @OLEResult int
DECLARE @FileID int
DECLARE @FileName VARCHAR(255)
DECLARE @Registro VARCHAR(MAX)
-- Es compatible con UNC ej \server\carpeta\archivo.txt
SELECT @Filename = 'c:\Salida.txt'
EXECUTE @OLEResult = sp_OACreate 'Scripting.FileSystemObject', @FS OUT
EXECUTE @OLEResult = sp_OAMethod @FS, 'OpenTextFile', @FileID OUT, @FileName, 8, True
DECLARE Registros CURSOR LOCAL FORWARD_ONLY
FOR SELECT CONVERT(VARCHAR,id) + ',' + name
FROM SYSOBJECTS
OPEN Registros
FETCH NEXT FROM Registros
INTO @Registro
WHILE @@FETCH_STATUS = 0
BEGIN
EXECUTE @OLEResult = sp_OAMethod @FileID, 'WriteLine', Null, @Registro
FETCH NEXT FROM Registros
INTO @Registro
END
EXECUTE @OLEResult = sp_OADestroy @FileID
EXECUTE @OLEResult = sp_OADestroy @FS
CLOSE Registros
DEALLOCATE Registros
If you want to avoid using the CURSOR, you should save everything in a single variable and save this:
EXECUTE @OLEResult = sp_OACreate 'Scripting.FileSystemObject', @FS OUT
EXECUTE @OLEResult = sp_OAMethod @FS, 'OpenTextFile', @FileID OUT, @FileName, 8, True
SELECT @Registro = ''
SELECT @Registro = @Registro + CONVERT(VARCHAR,id) + ',' + name + CHAR(10) + CHAR(13)
FROM SYSOBJECTS
EXECUTE @OLEResult = sp_OAMethod @FileID, 'WriteLine', Null, @Registro
EXECUTE @OLEResult = sp_OADestroy @FileID
EXECUTE @OLEResult = sp_OADestroy @FS
Important:
Keep in mind that this is a safety hole a little less dangerous than the one of xp_cmdshell
, but it is still a gap, so it is possible that if you are not allowed to use one, do not let yourself be used either the other.