Si vous êtes en mesure d'autoriser les procédures d'automatisation Ole, vous pouvez utiliser cette solution comme ci-dessous. Vous pouvez également créer une procédure stockée qui n'utilise pas le paramètre @OutputFileName et utiliser bcp pour enregistrer le contenu binaire dans un fichier (à l'aide d'un fichier de format qui exporte le contenu binaire sans ajouter de données au début de la sortie).
J'ai écrit ceci par frustration de ne pas pouvoir générer facilement des feuilles de calcul Excel avec le formatage de texte ou de nombre dont j'avais besoin. La procédure AddFileToArchive génère une archive zip contenant le contenu d'un fichier d'entrée et est utilisée en interne par GetExcelSpreadsheetData.
GetExcelSpreadsheetData génère une feuille de calcul pour une ou plusieurs tables temporaires et génère un classeur xml ouvert conforme. Les feuilles de calcul ont des en-têtes de colonne en caractères gras. Si vous produisez le fichier avec une extension .zip, vous verrez le contenu du fichier interne similaire à tout autre fichier .xlsx, mais les données sont stockées en interne en ligne plutôt que dans des valeurs partagées. Les feuilles de calcul peuvent être filtrées automatiquement en ajoutant l'option "filtre automatique".
Le formatage de la date est actuellement codé en dur sur jj/mm/aaaa, mais vous pouvez changer cela en modifiant ces lignes :
<numFmt formatCode="dd/mm/yyyy\ hh:mm" numFmtId="165"/>
<numFmt formatCode="hh:mm" numFmtId="166"/>
<numFmt formatCode="dd/mm/yyyy" numFmtId="167"/>
Désolé pour le manque de commentaires.
Crédit à La somme de contrôle SQL Server calcule-t-elle un CRC ? Sinon, comment puis-je faire en sorte que MS SQL calcule un CRC sur une colonne varchar arbitraire ? pour le code GetCRC32 utilisé s'il est exécuté sur SQL Server 2012 ou 2014.
Exemple d'utilisation en bas.
J'espère que vous trouverez cela utile. Cette procédure ne fonctionne pas sur SQL Server 2008R2 ou antérieur.
/****** Object: UserDefinedFunction [dbo].[GetCRC32] Script Date: 23/10/2020 4:52:31 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create function [dbo].[GetCRC32](@Text varchar(max)) returns binary(4) as
begin
declare
@crc bigint = 0xFFFFFFFF
,@Lookup varbinary(2048) = 0x0000000077073096EE0E612C990951BA076DC419706AF48FE963A5359E6495A30EDB883279DCB8A4E0D5E91E97D2D98809B64C2B7EB17CBDE7B82D0790BF1D911DB710646AB020F2F3B9714884BE41DE1ADAD47D6DDDE4EBF4D4B55183D385C7136C9856646BA8C0FD62F97A8A65C9EC14015C4F63066CD9FA0F3D638D080DF53B6E20C84C69105ED56041E4A26771723C03E4D14B04D447D20D85FDA50AB56B35B5A8FA42B2986CDBBBC9D6ACBCF94032D86CE345DF5C75DCD60DCFABD13D5926D930AC51DE003AC8D75180BFD0611621B4F4B556B3C423CFBA9599B8BDA50F2802B89E5F058808C60CD9B2B10BE9242F6F7C8758684C11C1611DABB6662D3D76DC419001DB710698D220BCEFD5102A71B1858906B6B51F9FBFE4A5E8B8D4337807C9A20F00F9349609A88EE10E98187F6A0DBB086D3D2D91646C97E6635C016B6B51F41C6C6162856530D8F262004E6C0695ED1B01A57B8208F4C1F50FC45765B0D9C612B7E9508BBEB8EAFCB9887C62DD1DDF15DA2D498CD37CF3FBD44C654DB261583AB551CEA3BC0074D4BB30E24ADFA5413DD895D7A4D1C46DD3D6F4FB4369E96A346ED9FCAD678846DA60B8D044042D7333031DE5AA0A4C5FDD0D7CC95005713C270241AABE0B1010C90C20865768B525206F85B3B966D409CE61E49F5EDEF90E29D9C998B0D09822C7D7A8B459B33D172EB40D81B7BD5C3BC0BA6CADEDB883209ABFB3B603B6E20C74B1D29AEAD547399DD277AF04DB261573DC1683E3630B1294643B840D6D6A3E7A6A5AA8E40ECF0B9309FF9D0A00AE277D079EB1F00F93448708A3D21E01F2686906C2FEF762575D806567CB196C36716E6B06E7FED41B7689D32BE010DA7A5A67DD4ACCF9B9DF6F8EBEEFF917B7BE4360B08ED5D6D6A3E8A1D1937E38D8C2C44FDFF252D1BB67F1A6BC57673FB506DD48B2364BD80D2BDAAF0A1B4C36034AF641047A60DF60EFC3A867DF55316E8EEF4669BE79CB61B38CBC66831A256FD2A05268E236CC0C7795BB0B4703220216B95505262FC5BA3BBEB2BD0B282BB45A925CB36A04C2D7FFA7B5D0CF312CD99E8B5BDEAE1D9B64C2B0EC63F226756AA39C026D930A9C0906A9EB0E363F720767850500571395BF4A82E2B87A147BB12BAE0CB61B3892D28E9BE5D5BE0D7CDCEFB70BDBDF2186D3D2D4F1D4E24268DDB3F81FDA836E81BE16CDF6B9265B6FB077E118B7477788085AE6FF0F6A7066063BCA11010B5C8F659EFFF862AE69616BFFD3166CCF45A00AE278D70DD2EE4E0483543903B3C2A7672661D06016F74969474D3E6E77DBAED16A4AD9D65ADC40DF0B6637D83BF0A9BCAE53DEBB9EC547B2CF7F30B5FFE9BDBDF21CCABAC28A53B3933024B4A3A6BAD03605CDD7069354DE572923D967BFB3667A2EC4614AB85D681B022A6F2B94B40BBE37C30C8EA15A05DF1B2D02EF8D
,@LenText int = len(@Text);
with x as (
select '' as Id
union all
select '' as Id from x
)
,y as (select top (cast(ceiling(sqrt(sqrt(@LenText))) as int)) '' as id from x)
,v as (
select top (@LenText) row_number() over (order by (select null)) as ID
from y cross join y as y2 cross join y as y3 cross join y as y4
)
SELECT @crc = (@crc / 256) ^ Substring(@Lookup, ((@crc & 0xFF) ^ Ascii(Substring(@Text, V.ID, 1))) * 4 + 1, 4)
FROM V
SET @crc = [email protected];
return cast(reverse(cast(@crc as varbinary(4))) as binary(4));
end
GO
/****** Object: UserDefinedFunction [dbo].[StringSplit2] Script Date: 23/10/2020 4:52:32 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create function [dbo].[StringSplit2] (@StringToSplit varchar(max), @Seperator char(1)) returns table
as
return (
with Split as (
select
1 as ValueOrder
,cast(1 as int) as ValueStartPos
,cast(charindex(@Seperator, @StringToSplit + @Seperator) as int) as ValueEndPos
union all
select
ValueOrder + 1 as ValueOrder
,ValueEndPos + 1 as ValueStartPos
,cast(charindex(@Seperator, @StringToSplit + @Seperator, ValueEndPos + 1) as int) as ValueEndPos
from Split
where ValueEndPos <> 0
)
select
ValueOrder
,substring(@StringToSplit, ValueStartPos, case when ValueEndPos = 0 then 0 else ValueEndPos-ValueStartPos end) as value
from Split
where ValueEndPos <> 0
)
GO
/****** Object: StoredProcedure [dbo].[AddFileToArchive] Script Date: 23/10/2020 4:52:32 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create procedure [dbo].[AddFileToArchive](@FileName varchar(max), @FileContents varbinary(max), @ArchiveData varbinary(max) output, @ArchiveInfo binary(10) output)
as
begin
set nocount on;
declare
@LocalFileHeaderSignature binary(4) = 0x504b0304
,@CentralDirectoryFileHeaderSignature binary(4) = 0x504b0102
,@EndOfCentralDirectorySignature binary(4) = 0x504b0506
,@VersionNeededToExtract binary(2) = 0x1400
,@VersionMadeBy binary(2) = 0x1400
,@GeneralPurposeBitFlag binary(2) = 0x0000
,@CompressionMethod binary(2) = 0x0000--0x0800
,@CompressionMethodDeflate binary(2) = 0x0800
,@FileLastModificationTime binary(2) = 0xA351 -- dummy time
,@FileLastModificationDate binary(2) = 0x6250 -- dummy date
,@currentDateTime datetime = getdate()
,@CRC32 binary(4)
,@CompressedSize int
,@UncompressedSize int
,@FileNameLength smallint
,@ExtraFieldLength smallint = 0
,@FileCommentLength smallint = 0
,@CommentLength smallint = 0
,@NumberOfThisDisk smallint = 0
,@DiskNumberWhereFileStarts smallint = 0
,@InternalFileAttributes binary(2) = 0x0100
,@ExternalFileAttributes binary(4) = 0x20000000
,@LocalFileRecordLength int
,@LocalFileRecord varbinary(max)
,@CompressedFileContents varbinary(max)
,@LenCompressedFileContents int
,@FileCRC32 binary(4)
,@OffsetOfStartOfCentralDirectory int
,@CentralDirectoryRecord varbinary(max)
,@EndOfCentralDirectoryRecord varbinary(max)
,@sql nvarchar(max)
,@OtherFileCount smallint
,@FileOffset int
,@SizeOfCentralDirectory int;
set @OtherFileCount = IsNull(cast(SubString(@ArchiveInfo, 1, 2) as smallint), 0);
set @FileOffset = IsNull(cast(SubString(@ArchiveInfo, 3, 4) as int), 0);
set @SizeOfCentralDirectory = IsNull(cast(SubString(@ArchiveInfo, 7, 4) as int), 0);
set @FileLastModificationTime = cast(reverse(cast((datepart(ss, @currentDateTime) / 2) | (32 * datepart(mi, @currentDateTime)) | (2048 * datepart(hh, @currentDateTime)) as binary(2))) as binary (2));
set @FileLastModificationDate = cast(reverse(cast((datepart(dd, @currentDateTime)) | (32 * datepart(mm, @currentDateTime)) | (512 * (datepart(yy, @currentDateTime) - 1980)) as binary(2))) as binary (2));
-- for SQL Server 2016 or higher compress the file contents
if cast(serverproperty('ProductMajorVersion') as int) > 12 -- SQL Server 2016+
begin
exec sp_executesql
@stmt = N'set @CompressedFileContents = compress(@FileContents)'
,@params = N'@FileContents varbinary(max), @CompressedFileContents varbinary(max) output'
,@CompressedFileContents = @CompressedFileContents output
,@FileContents = @FileContents;
set @FileCRC32 = substring(@CompressedFileContents, len(@CompressedFileContents) - 7, 4);
set @CompressionMethod = @CompressionMethodDeflate;
end
else
begin
set @CompressedFileContents = 0x00000000000000000000 + @FileContents + 0x0000000000000000;
exec sp_executesql
@stmt = N'set @FileCRC32 = dbo.GetCRC32(@FileContents)'
,@params = N'@FileContents varbinary(max), @FileCRC32 binary(4) output'
,@FileContents = @FileContents
,@FileCRC32 = @FileCRC32 output;
end;
set @LenCompressedFileContents = len(@CompressedFileContents);
set @CompressedSize = @LenCompressedFileContents - 18;
set @UncompressedSize = len(@FileContents);
set @FileNameLength = len(@FileName);
set @LocalFileRecord =
@LocalFileHeaderSignature
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
+cast(reverse(cast(@CompressedSize as binary(4))) as binary(4))
+cast(reverse(cast(@UncompressedSize as binary(4))) as binary(4))
+cast(reverse(cast(@FileNameLength as binary(2))) as binary(2))
+cast(reverse(cast(@ExtraFieldLength as binary(2))) as binary(2))
+cast(@FileName as varbinary(max))
+substring(@CompressedFileContents, 11, @LenCompressedFileContents - 18);
set @CentralDirectoryRecord =
@CentralDirectoryFileHeaderSignature
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
+cast(reverse(cast(@CompressedSize as binary(4))) as binary(4))
+cast(reverse(cast(@UncompressedSize as binary(4))) as binary(4))
+cast(reverse(cast(@FileNameLength as binary(2))) as binary(2))
+cast(reverse(cast(@ExtraFieldLength as binary(2))) as binary(2))
+cast(reverse(cast(@FileCommentLength as binary(2))) as binary(2))
+cast(reverse(cast(@DiskNumberWhereFileStarts as binary(2))) as binary(2))
[email protected]
[email protected]
+cast(reverse(cast(@FileOffset as binary(4))) as binary(4))
+cast(@FileName as varbinary(max));
set @SizeOfCentralDirectory = @SizeOfCentralDirectory + len(@CentralDirectoryRecord);
set @LocalFileRecordLength= len(@LocalFileRecord)
set @OffsetOfStartOfCentralDirectory = @FileOffset + @LocalFileRecordLength;
set @EndOfCentralDirectoryRecord =
@EndOfCentralDirectorySignature
+cast(reverse(cast(@NumberOfThisDisk as binary(2))) as binary(2))
+cast(reverse(cast(@NumberOfThisDisk as binary(2))) as binary(2)) -- Disk where central directory starts
+cast(reverse(cast(@OtherFileCount + cast(1 as smallint) as binary(2))) as binary(2)) -- Number of central directory records on this disk
+cast(reverse(cast(@OtherFileCount + cast(1 as smallint) as binary(2))) as binary(2)) -- Total number of central directory records
+cast(reverse(cast(@SizeOfCentralDirectory as binary(4))) as binary(4))
+cast(reverse(cast(@OffsetOfStartOfCentralDirectory as binary(4))) as binary(4))
+cast(reverse(cast(@CommentLength as binary(2))) as binary(2))
if @ArchiveInfo is null
set @ArchiveData = @LocalFileRecord + @CentralDirectoryRecord + @EndOfCentralDirectoryRecord
else
set @ArchiveData =
SubString(@ArchiveData, 1, @FileOffset) + @LocalFileRecord
+SubString(@ArchiveData, @FileOffset + 1, @SizeOfCentralDirectory - len(@CentralDirectoryRecord)) + @CentralDirectoryRecord
[email protected];
set @ArchiveInfo =
cast(@OtherFileCount + 1 as binary(2))
+ cast(@FileOffset + @LocalFileRecordLength as binary(4))
+ cast(@SizeOfCentralDirectory as binary(4));
-- select @ArchiveInfo as ArchiveInfo, @LocalFileRecord as LocalFileRecord,@CentralDirectoryRecord as CentralDirectoryRecord, @EndOfCentralDirectoryRecord as EndOfCentralDirectoryRecord
return;
end
GO
/****** Object: StoredProcedure [dbo].[GetExcelSpreadsheetData] Script Date: 23/10/2020 4:52:32 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE procedure [dbo].[GetExcelSpreadsheetData](@SheetName varchar(31) = null, @Worksheets varchar(max) = null, @WorkbookData varbinary(max) = null output, @OutputFileName nvarchar(500) = null)
as
set nocount on;
declare
@LocalFileRecords varbinary(max)
,@CentralDirectoryRecords varbinary(max)
,@EndOfCentralDirectoryRecord varbinary(max)
,@OtherFileCount smallint
,@FileOffset int
,@SizeOfCentralDirectory int
,@NumberOfWorksheets smallint
,@CurrentWorksheet smallint = 1
,@sql nvarchar(max) = N''
,@rowcountsql nvarchar(max)
,@rowcount int
,@colcount int
,@datatable varchar(100)
,@RowDataXML nvarchar(max)
,@SelectOutput bit = 0
,@ArchiveInfo binary(10)
,@WorksheetFileName varchar(50)
,@ObjectToken int
,@AutoFilterXML nvarchar(max) = N''
,@_Content_Types__xml__sheets nvarchar(max)
,@_Content_Types__xml varbinary(max)
,@Workbook_xml_temp nvarchar(max)
,@Workbook_xml varbinary(max)
,@_Rels_workbook_xml_rels varbinary(max)
,@styles_xml varbinary(max) = cast(N'<?xml version="1.0" encoding="utf-16"?>
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<numFmts count="3">
<numFmt formatCode="dd/mm/yyyy\ hh:mm" numFmtId="165"/>
<numFmt formatCode="hh:mm" numFmtId="166"/>
<numFmt formatCode="dd/mm/yyyy" numFmtId="167"/>
</numFmts>
<fonts count="7">
<font> <sz val="11"/> <name val="Calibri"/><family val="2" /><scheme val="minor" /></font>
<font> <sz val="11"/><color rgb="FFFF0000" /><name val="Calibri"/><family val="2" /><scheme val="minor" /></font>
<font><b/><sz val="11"/> <name val="Calibri"/><family val="2" /><scheme val="minor" /></font>
<font><i/><sz val="11"/> <name val="Calibri"/><family val="2" /><scheme val="minor" /></font>
<font> <sz val="11"/><color rgb="FF0070C0" /><name val="Calibri"/><family val="2" /><scheme val="minor" /></font>
<font> <sz val="20"/> <name val="Calibri"/><family val="2" /><scheme val="minor" /></font>
<font> <sz val="11"/> <name val="Courier"/><family val="3" /> </font>
</fonts>
<fills count="2">
<fill>
<patternFill patternType="none" />
</fill>
<fill>
<patternFill patternType="gray125" />
</fill>
</fills>
<borders count="1">
<border>
<left />
<right />
<top />
<bottom />
<diagonal />
</border>
</borders>
<cellStyleXfs count="1">
<xf numFmtId="0" fontId="0" fillId="0" borderId="0" />
</cellStyleXfs>
<cellXfs count="10">
<xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0" />
<xf numFmtId="0" fontId="2" fillId="0" borderId="0" xfId="0" applyFont="1" />
<xf numFmtId="0" fontId="3" fillId="0" borderId="0" xfId="0" applyFont="1" />
<xf numFmtId="0" fontId="4" fillId="0" borderId="0" xfId="0" applyFont="1" />
<xf numFmtId="0" fontId="1" fillId="0" borderId="0" xfId="0" applyFont="1" />
<xf numFmtId="0" fontId="5" fillId="0" borderId="0" xfId="0" applyFont="1" />
<xf numFmtId="0" fontId="6" fillId="0" borderId="0" xfId="0" applyFont="1" />
<xf numFmtId="165" borderId="0" fillId="0" fontId="0" xfId="0" applyNumberFormat="1"/>
<xf numFmtId="166" borderId="0" fillId="0" fontId="0" xfId="0" applyNumberFormat="1"/>
<xf numFmtId="167" borderId="0" fillId="0" fontId="0" xfId="0" applyNumberFormat="1"/>
</cellXfs>
<cellStyles count="1">
<cellStyle name="Standard" xfId="0" builtinId="0" />
</cellStyles>
<dxfs count="0" />
<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleLight16" />
</styleSheet>' as varbinary(max))
,@worksheet_xml varbinary(max)
,@_rels_rels varbinary(max) = cast(N'<?xml version="1.0" encoding="UTF-16" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="workbook.xml"/>
</Relationships>' as varbinary(max));
-- if Worksheets is not specified, set @Worksheets to @SheetName + / + #data
if @Worksheets is null-- @SheetName is not null and @Worksheets is null
set @Worksheets = IsNull(@SheetName, 'Sheet1') + '/#data';
-- if a non-null value is passed in @WorkbookData, the output should be set in the optional output parameter @WorkbookData
-- if a null or no value is passed in @WorkbookData, the output will be selected at the end of the procedure
if @WorkbookData is null and @OutputFileName is null
set @SelectOutput = 1
else
set @WorkbookData = null;
select
Worksheet.ValueOrder as WorksheetNumber
,WorksheetTable.ValueOrder as ColumnNumber
,WorksheetTable.value
,WorksheetTableOptions.ValueOrder as WorksheetOptionNumber
,WorksheetTableOptions.value as WorksheetOption
into #WorksheetConfig
from dbo.StringSplit2(@Worksheets, '|') as Worksheet
cross apply dbo.StringSplit2(Worksheet.value, '/') as WorksheetTable
cross apply dbo.StringSplit2(WorksheetTable.value, '~') as WorksheetTableOptions;
select
@NumberOfWorksheets = max(WorksheetNumber)
from #WorksheetConfig;
-- xml for @Workbook_xml
with xmlnamespaces (
'http://schemas.openxmlformats.org/officeDocument/2006/relationships' as r
,default 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'
)
select @Workbook_xml_temp = (
select
Worksheet.value as [sheet/@name]
,Worksheet.WorksheetNumber as [sheet/@sheetId]
,'rId' + cast(Worksheet.WorksheetNumber + 1 as varchar) as [sheet/@r:id]
from #WorksheetConfig Worksheet
where ColumnNumber = 1
for xml path('sheets'), root('workbook')
);
set @Workbook_xml = cast(Replace(@Workbook_xml_temp, '</sheets><sheets>', '') as varbinary(max));
-- xml for @_Content_Types__xml
select @_Content_Types__xml__sheets = (
select
'/sheet' + cast(Worksheet.WorksheetNumber as varchar) + '.xml' as [@PartName]
,'application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml' as [@ContentType]
from #WorksheetConfig Worksheet
where ColumnNumber = 1
for xml path('Override')
);
-- xml for @_Rels_workbook_xml_rels
with xmlnamespaces (
default 'http://schemas.openxmlformats.org/package/2006/relationships'
)
,x as (
select
'rId1' as [@Id]
,'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles' as [@Type]
,'styles.xml' as [@Target]
union all
select
'rId' + cast(Worksheet.WorksheetNumber + 1 as varchar) as [@Id]
,'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet' as [@Type]
,'sheet' + cast(Worksheet.WorksheetNumber as varchar) + '.xml' as [@Target]
from #WorksheetConfig Worksheet
where ColumnNumber = 1
)
select @_Rels_workbook_xml_rels = cast((
select
*
from x
for xml path('Relationship'), root('Relationships')
) as varbinary(max));
set @_Content_Types__xml = cast(N'<?xml version="1.0" encoding="UTF-16" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
<Override PartName="/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
<Override PartName="/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>
' + @_Content_Types__xml__sheets + '
</Types>' as varbinary(max));
exec dbo.AddFileToArchive
@FileName = '[Content_Types].xml'
,@FileContents = @_Content_Types__xml
,@ArchiveData = @WorkbookData output
,@ArchiveInfo = @ArchiveInfo output;
exec dbo.AddFileToArchive
@FileName = '_rels/.rels'
,@FileContents = @_rels_rels
,@ArchiveData = @WorkbookData output
,@ArchiveInfo = @ArchiveInfo output;
exec dbo.AddFileToArchive
@FileName = '_rels/workbook.xml.rels'
,@FileContents = @_Rels_workbook_xml_rels
,@ArchiveData = @WorkbookData output
,@ArchiveInfo = @ArchiveInfo output;
exec dbo.AddFileToArchive
@FileName = 'workbook.xml'
,@FileContents = @workbook_xml
,@ArchiveData = @WorkbookData output
,@ArchiveInfo = @ArchiveInfo output;
exec dbo.AddFileToArchive
@FileName = 'styles.xml'
,@FileContents = @styles_xml
,@ArchiveData = @WorkbookData output
,@ArchiveInfo = @ArchiveInfo output;
while @CurrentWorksheet <= @NumberOfWorksheets
begin
set @sql = '';
select
@datatable = value
from #WorksheetConfig
where WorksheetNumber = @CurrentWorksheet
and ColumnNumber = 2;
select @sql +=
',''' + rtrim(case when column_id > 26 then char(64 + ((column_id -1) / 26)) + char(65 + ((column_id -1) % 26)) else char(64 + column_id) end) + ''' + cast(__r__ as varchar) as [c/@r]'
+ case when sc.system_type_id in (40, 41, 42, 43, 48, 52, 56, 58, 61, 62, 104, 106, 108, 127) then '' else ',''inlineStr'' as [c/@t]' end -- non text data types
+ case
when sc.system_type_id in (42, 43, 58, 61) then ',7 as [c/@s]' -- datetime2, datetimeoffset smalldatetime, datetime
when sc.system_type_id in (41) then ',8 as [c/@s]' -- time
when sc.system_type_id in (40) then ',9 as [c/@s]' -- date
else ''
end -- smalldatetime, datetime, time, date
+ ',' + case
when sc.system_type_id in (40, 58, 61) then 'cast(cast(' + quotename(name) + 'as datetime) as float) + case when ''19000301'' > ' + quotename(name) + ' then 1 else 2 end'
when sc.system_type_id in (42, 43) then 'cast(cast(cast(' + quotename(name) + ' as date) as datetime) as float) + datepart(hh, ' + quotename(name) + ') / 24.00000 + datepart(mi, ' + quotename(name) + ') / 1440.00000 + datepart(ss, ' + quotename(name) + ') / 86400.00000 + datepart(ms, ' + quotename(name) + ') / 86400000.00000 + case when ''19000301'' > ' + quotename(name) + ' then 1 else 2 end'
when sc.system_type_id in (41) then 'cast(cast(' + quotename(name) + ' as datetime) as float)' else quotename(name)
end
+ case when sc.system_type_id in (40, 41, 42, 43, 48, 52, 56, 58, 61, 62, 104, 106, 108, 127) then ' as [c/v]' else ' as [c/is/t]' end
+ ','''''
from tempdb.sys.columns sc
where object_id = object_id('tempdb.dbo.' + @datatable)
order by column_id;
set @sql = right(@sql, len(@sql) - 1);
set @sql =
'select @xml = (select(cast((
select
1 as [@r]
,(
select
rtrim(case when column_id > 26 then char(64 + ((column_id -1) / 26)) + char(65 + ((column_id -1) % 26)) else char(64 + column_id) end) + ''1'' as [c/@r]
,1 as [c/@s]
,''inlineStr'' as [c/@t]
,name as [c/is/t]
from tempdb.sys.columns sc
where object_id = object_id(''' + case when left(@datatable, 1) = '#' then 'tempdb.dbo.' else '' end + Replace(@datatable, '''', '''''') + ''')
order by column_id
for xml path(''''), type
)
from (select 1 as c1) x
for xml path(''row''))
as nvarchar(max))))
+
(select(IsNull(cast((
select
__r__ as [@r]
,(
select
' + @sql + '
for xml path(''''), type
)
from (select row_number() over (order by (select 1)) + 1 as __r__, * from ' + Replace(@datatable, '''', '''''') + ') d
for xml path(''row''))
as nvarchar(max)), '''')));';
exec sp_executesql @stmt = @sql, @params = N'@xml nvarchar(max) output', @xml = @RowDataXML output;
if exists (select * from #WorksheetConfig where WorksheetNumber = @CurrentWorksheet and ColumnNumber = 3 and WorksheetOption = 'autofilter')
begin
set @rowcountsql = N'select @rowcount = count(*) + 1 from ' + @datatable;
exec sp_executesql @stmt = @rowcountsql, @params = N'@rowcount int output', @rowcount = @rowcount output;
select
@colcount = count(*)
from tempdb.sys.columns sc
where object_id = object_id('tempdb.dbo.' + @datatable);
select @AutoFilterXML = N'<autoFilter ref="A1:'
+ rtrim(case when @colcount > 26 then char(64 + ((@colcount -1) / 26)) + char(65 + ((@colcount -1) % 26)) else char(64 + @colcount) end) + cast(@rowcount as nvarchar)
+ '" xr:uid="{' + cast(newid() as nvarchar(36)) + '}"/>';
end;
set @worksheet_xml = cast(
'<?xml version="1.0" encoding="UTF-16" standalone="yes"?><worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision"><sheetData>' + @RowDataXML + '</sheetData>' + @AutoFilterXML + '</worksheet>'
as varbinary(max));
set @WorksheetFileName = 'sheet' + cast(@CurrentWorksheet as varchar) + '.xml';
exec dbo.AddFileToArchive
@FileName = @WorksheetFileName
,@FileContents = @worksheet_xml
,@ArchiveData = @WorkbookData output
,@ArchiveInfo = @ArchiveInfo output;
set @CurrentWorksheet = @CurrentWorksheet +1;
set @AutoFilterXML = N'';
end;
if @SelectOutput = 1
select @WorkbookData as ExcelSpreadsheetData;
if @OutputFileName is not null and (select value_in_use from sys.configurations where name = 'Ole Automation Procedures') = 1
begin
exec sp_oacreate 'ADODB.Stream', @ObjectToken output;
exec sp_oasetproperty @ObjectToken, 'type', 1;
exec sp_oamethod @ObjectToken, 'open';
exec sp_oamethod @ObjectToken, 'write', null, @WorkbookData;
exec sp_oamethod @ObjectToken, 'savetofile', null, @OutputFileName, 2;
exec sp_oamethod @ObjectToken, 'close';
exec sp_oadestroy @ObjectToken;
end;
return;
GO
Exemple d'utilisation :
select * into #systables from sys.tables;
select * into #syscolumns from sys.columns;
select * into #systypes from sys.types;
exec dbo.GetExcelSpreadsheetData
@Worksheets = 'sys.tables/#systables/autofilter|sys.columns/#syscolumns/autofilter|sys.types/#systypes'
,@OutputFileName = 'c:\tmp\ExcelData.xlsx';
drop table #systables;
drop table #syscolumns;
drop table #systypes;
Edit :je suis d'accord avec tous ceux qui disent que c'est une chose ridicule à faire dans TSQL. Cela semblait être une mauvaise idée à l'époque, mais cela me facilite la vie.