SSMS
 sql >> Cơ Sở Dữ Liệu >  >> Database Tools >> SSMS

SSMS:Tự động lưu nhiều bộ kết quả từ cùng một tập lệnh SQL vào các tab riêng biệt trong Excel?

Nếu bạn có thể cho phép Quy trình tự động hóa Ole, bạn có thể sử dụng giải pháp này như bên dưới. Bạn cũng có thể tạo một thủ tục được lưu trữ không sử dụng tham số @OutputFileName và sử dụng bcp để lưu nội dung nhị phân vào một tệp (sử dụng tệp định dạng xuất nội dung nhị phân mà không cần thêm dữ liệu vào đầu đầu ra).

Tôi viết điều này vì thất vọng vì không thể dễ dàng tạo Bảng tính Excel với định dạng văn bản hoặc số mà tôi yêu cầu. Thủ tục AddFileToArchive tạo một kho lưu trữ zip có chứa nội dung của tệp đầu vào và được GetExcelS SpreadsheetData sử dụng nội bộ.

GetExcelS SpreadsheetData tạo một trang tính cho một hoặc nhiều bảng tạm thời và xuất ra một sổ làm việc xml mở tuân thủ. Trang tính có tiêu đề cột bằng phông chữ đậm. Nếu bạn xuất tệp có phần mở rộng .zip, bạn sẽ thấy nội dung tệp bên trong tương tự như bất kỳ tệp .xlsx nào khác, tuy nhiên dữ liệu được lưu trữ bên trong nội tuyến thay vì ở các giá trị được chia sẻ. Trang tính có thể được tự động lọc bằng cách thêm tùy chọn "tự động lọc".

Định dạng ngày hiện được mã hóa cứng thành dd / mm / yyyy tuy nhiên bạn có thể thay đổi định dạng đó bằng cách thay đổi các dòng sau:

    <numFmt formatCode="dd/mm/yyyy\ hh:mm" numFmtId="165"/>
    <numFmt formatCode="hh:mm" numFmtId="166"/>
    <numFmt formatCode="dd/mm/yyyy" numFmtId="167"/>

Xin lỗi vì thiếu ý kiến.

Ghi có cho SQL Server CheckSum có tính CRC không? Nếu không, làm cách nào tôi có thể lấy MS SQL để tính CRC trên một cột varchar tùy ý? cho mã GetCRC32 được sử dụng nếu được thực thi trên SQL Server 2012 hoặc 2014.

Ví dụ về cách sử dụng ở dưới cùng.

Hy vọng rằng bạn sẽ thấy điều này hữu ích. Quy trình này không hoạt động trên SQL Server 2008R2 trở xuống.

/****** 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

Cách sử dụng ví dụ:

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;

Chỉnh sửa:Tôi đồng ý với bất kỳ ai nhận xét rằng đây là một điều vô lý để làm trong TSQL. Đó có vẻ là một ý kiến ​​tồi vào thời điểm đó, tuy nhiên nó đã giúp cuộc sống của tôi dễ dàng hơn.



  1. DBeaver
  2.   
  3. phpMyAdmin
  4.   
  5. Navicat
  6.   
  7. SSMS
  8.   
  9. MySQL Workbench
  10.   
  11. SQLyog
  1. Không thể kết nối với SQL Server trong miền khác bằng SSMS và Trình quản lý thông tin đăng nhập Windows 7

  2. Tạo mục menu tùy chỉnh trong Object Explorer

  3. ssm sao chép cơ sở dữ liệu

  4. SQL Server Management Studio:Mở bảng để chỉnh sửa thông qua phím tắt

  5. Máy khách SQL Server đơn giản tốt