【问题标题】:Export Multiple Dynamically Pivoted SQL Query Results to Excel将多个动态透视 SQL 查询结果导出到 Excel
【发布时间】:2020-11-09 04:41:03
【问题描述】:

我有一个从 SQL Server Management Studio (v18.5) 执行的批处理查询,它有多个动态片段并生成多个查询结果,如果可能的话,我想从 SSMS 控制台自动导出到 Excel。

在批处理查询中,我首先从表中的 1 列中选择一个唯一的集合值,然后遍历该列表以使用列表中的值构建动态数据透视查询。每个数据透视查询的每个值都会有一组不同的结果。

例如:我循环的唯一列表:

Type
-----
Fan
Compressor
Belt
Motor
Filter

Fan 的数据透视查询结果将具有一组独特的列,这些列与 Compressor 的数据透视查询结果不同。

风扇轴列

FanID, Speed, Weight, Blade Size, RPM

压缩机枢轴列

CompressorID, HP, Voltage, Amps, Height, 

每次循环浏览类型列表时,我都想将旋转后的查询结果导出到 Excel 文件。理想情况下,我想导出到 1 个工作簿,每个类型的旋转查询结果都有自己的工作表。由于每个透视查询结果都会有一组不同的列,因此我无法将所有查询结果编译到 1 个表中,然后导出到 Excel(或 csv)。尽量避免有多个文件,每种类型一个。

更新:

我已将以下内容添加到我的批处理查询中:

INSERT INTO OPENROWSET(''Microsoft.ACE.OLEDB.12.0'',''Excel 12.0; Database=C:\temp\tesxt.xlsx;'',''SELECT * FROM [Sheet1$]'')

但我收到以下错误:

Cannot create an instance of OLE DB provider "Microsoft.ACE.OLEDB.12.0" for linked server "(null)"

我在尝试上面的代码之前运行了这两个命令:

EXEC sp_configure 'show advanced options', 1
RECONFIGURE
EXEC sp_configure 'Ad Hoc Distributed Queries', 1
RECONFIGURE

更新: 我希望有一个糟糕的导出选项可以消除编写应用程序的需要。

我尝试了 BCP 方法,但无法让它发挥作用。我将服务器名称更改为我的,将数据库名称更改为我的;没有运气。 @sql 变量是我的动态数据透视查询。尝试了不同的 bcp 命令参数,但没有成功。

更新: 靠近一点;我用一个简单的选择查询替换了上面 bcp 命令中的 @sql 并执行了该命令,为类型列表中的每个“类型”创建了一个新的 .csv 文件;在复杂的动态数据透视@sql 字符串中一定有 bcp 不喜欢的东西。无论如何,我知道将 bcp 查询结果导出到 csv 文件的底层管道正在工作。

更新:

这是@sqlCommandForBcp

set @sqlCommandForBcp = 'bcp "'+ @sqlForPivot + '" queryout "' + @filePath + @fileName + '" -S CLT00ZB1\SQLEXPRESS2019 -T -t , -d Repository -c'

这是@sqlCommandForBcp 的打印输出,其中包括一个真实数据透视查询的示例。类型列表的每次迭代都会生成一个具有不同列的新数据透视查询。

bcp "SELECT ProductID, KWGAID, ShortDesc, VendorID, Segment, Category, Type, SubType,[Airflow], [Amperage], [Bearings], [Cross Reference], [Diameter], [Enclosure], [Footnotes], [Frame], [Frequency], [Item], [Motor Type], [OEM], [Options], [Power], [Replacing], [Rotation], [RPM], [RPM-Range], [Series-Brand], [Shaft], [Speed], [Stack Size], [Voltage] 
            FROM
            (
                SELECT ''+ CONVERT(nvarchar(8), a.SeqNum) + '  |  ' + '' + a.TypeID + '' + '  |  ' + CONVERT(nvarchar(1), a.IncludeName) + '  |     ' + 
                         a.Value as Value, a.Name, p.KWGAID, p.SeqNum as ProductID, p.ShortDescription as ShortDesc, 
                            p.VendorID, p.VendorPartNumber, s.Name as Segment, c.Name as Category, 
                            t.Name as Type, st.Name as SubType

            FROM            Product p INNER JOIN
                                     Segment s ON p.SegmentID = s.ID INNER JOIN
                                     Category c ON p.CategoryID = c.ID INNER JOIN
                                     Type t ON p.TypeID = t.ID INNER JOIN
                                     Vendor v ON p.VendorID = v.ID INNER JOIN
                                     SubType st ON p.SubTypeID = st.ID INNER JOIN
                                     Attribute a ON p.SeqNum = a.ProductSeqNum INNER JOIN
                                     AttributeType at ON a.TypeID = at.ID

            Where v.ID = 132 AND c.Name like 'Blower Motors' 

            ) as PivotData
            PIVOT
            (
                Max(Value)
                For Name IN ([Airflow], [Amperage], [Bearings], [Cross Reference], [Diameter], [Enclosure], [Footnotes], [Frame], [Frequency], [Item], [Motor Type], [OEM], [Options], [Power], [Replacing], [Rotation], [RPM], [RPM-Range], [Series-Brand], [Shaft], [Speed], [Stack Size], [Voltage])
            ) as PivotResults Order by Segment, Category, Type, SubType, ShortDesc" queryout "C:\Temp\Blower Motors.csv" -S CLT00ZB1\SQLEXPRESS2019 -T -t , -d Repository -c

更新:

又向前迈了一步。将数据透视查询结果插入到临时全局表中,然后在 bcp 命令中选择该表即可!我现在将结果导出到单个 csv 文件;但是,我看到了两个问题。 1. 结果不包括列标题;我必须拥有这些,并且每个数据透视查询结果都会有不同的列。 2. 查询结果中有逗号,就是把导出的结果丢掉了。我通读了 bcp 文档,没有看到强制列标题的命令开关;也不知道如何处理查询结果中的逗号。

更新: 我最终放弃了使用 SSMS 的 tSQL 方法,开始用另一种语言编写解决方案。这仅用于临时清理项目,而不是长期生产解决方案。我正在使用通过 ODBC 和一些 VBA 链接的 Access 来处理遍历类型列表并将透视(Access 中的 CrossTab)结果导出到 Excel。使用 VBA,我拥有动态创建工作簿和插入工作表等所需的一切。

我在 SQL 中学到了一些关于 bcp 和链接服务器的知识,但是对于我想要做的事情,没有一个非常简单的解决方案。

不确定谁应该在这里获得积分。感谢大家的投入。

【问题讨论】:

  • 你能显示SQL吗?如果您需要帮助。
  • 您是否尝试检查此线程的答案? stackoverflow.com/questions/36987636/…
  • 这篇文章帮助我解决了这个问题sqlwithmanoj.com/2012/07/10/…
  • 我贴了上面的SQL;里面有一些它不喜欢的东西,只是不确定是什么。至于 Kokokoko 的 cmets,谢谢,我看了这两个...在链接服务器方法中遇到了权限问题...感觉 bcp 是“这个”关闭...哈哈。

标签: sql-server tsql pivot ssms export-to-excel


【解决方案1】:

使用另一种语言构建文件会更好。比如有很多techniques生成文件使用.net或者你可以使用power-shell。这个想法是将您的代码包装在一个存储过程中并从其他语言中调用它。

在 SQL Server 的上下文中,您可以使用BCP 生成一个 CSV 文件,该文件可以供 Excel 使用。

您需要启用xp_cmdshell 才能在T-SQL 的上下文中执行bcp 命令:

 -- To allow advanced options to be changed.
EXEC sp_configure 'show advanced options', 1
GO
-- To update the currently configured value for advanced options.
RECONFIGURE
GO
-- To enable the feature.
EXEC sp_configure 'xp_cmdshell', 1
GO
-- To update the currently configured value for this feature.
RECONFIGURE
GO

然后,您只需:

DECLARE       @sqlCommand   VARCHAR(1000)
DECLARE       @filePath     VARCHAR(100)
DECLARE       @fileName     VARCHAR(100)

SET    @filePath = 'C:\Temp\'
SET    @fileName = 'MyFile_' + CONVERT(VARCHAR, GETDATE(), 112) + '_' + CAST(DATEPART(HOUR, GETDATE()) AS VARCHAR) + '_' + CAST(DATEPART(MINUTE,GETDATE()) AS VARCHAR) + '.csv'

SET  @sqlCommand = 'bcp "SELECT 1 AS A, 2 AS B, 3 AS C UNION ALL SELECT 4, 5, 6" queryout "' +
                    @filePath + @fileName +
                    ' " -S RMVNSQL01\INST1 -T -t, -d smModel -c'

PRINT       @sqlCommand

EXEC   master..xp_cmdshell @sqlCommand

GO

这将生成以下文件MyFile_20200729_9_1.csv

另外,如果您想使用 SQL Server 生成 excel 文件并且想要拥有单独的工作表,您可能需要使用 SQL Server Reporting Server。问题在于您的数据是动态的,您将面临将其可视化的困难。最好只是准备好它并在那里执行PIVOT


为了添加标题,在开头插入一行。像这样的:

SELECT 'ProductID', 'KWGAID', 'ShortDesc', 'VendorID', 'Segment', 'Category', 'Type', 'SubType', 'Airflow', 'Amperage', 'Bearings', 'Cross Reference', 'Diameter', 'Enclosure', 'Footnotes', 'Frame', 'Frequency', 'Item', 'Motor Type', 'OEM', 'Options', 'Power', 'Replacing', 'Rotation', 'RPM', 'RPM-Range', 'Series-Brand', 'Shaft', 'Speed', 'Stack Size', 'Voltage'
UNION ALL
...

【讨论】:

  • 我明白关于用另一种语言写这篇文章;我希望有一个快速而肮脏的选项可以直接从 SSMS 导出文件。我认为 bcp 会起作用,但它不喜欢某些东西。我发布了我正在使用的命令和错误结果。
  • 还没有;试图让 ACE OLEDB 选项工作。
  • @GJGerson 告诉我你正在使用的代码和你得到的错误。
  • 感谢您的帮助;如上所述,我将用另一种语言编写解决方案;爬山太多了;正如你提到的,tSQL 不是这个项目的最佳解决方案。不知道如何处理积分;你和 Mitz 非常有帮助。不知道如何分割点...大声笑
  • @GJGerson,不客气。 .net 上有非常好的库用于生成 xls 文件。它们提供了许多选项 - 甚至是格式化,所以我相信使用这些选项你会很轻松地完成任务。
【解决方案2】:

如果您可以在服务器上存储一个空白的excel文件并使用xp_cmdshell将其复制到每个文件的新位置,您可以使用:

INSERT INTO OPENROWSET('Microsoft.ACE.OLEDB.12.0', 'Excel 12.0; HDR=YES;IMEX=0;Database=c:\mitz\somex2.xlsx', 'Select * from [Sheet1$]')
SELECT * from mytable

这会将表格中的数据插入到 Sheet1 中。如果这是您第一次使用它,您需要安装 Ace Oledb 并进行一些调整。

如果不能选择空白文件,您也可以使用 openrowset 创建一个新的 XLSX 文件,但它有一个随机的工作表名称。这样创建之后,您可以使用其他选择来获取工作表名称,然后将我上面的插入语句转换为动态 SQL,以便工作表名称是动态的。因此,简单的方法是创建一个空白的 template.xlsx 文件并将其复制以用于您的 excel 文件导出。

要设置 Ace OLEDB,请参阅 this link

编辑2: 如果您需要可变列名:

  • 创建一个 excel 文件,其中一行在第一行包含一些文本。使用与要导出的最大列数一样多的单元格。这将是您的模板文件

  • 对于每次导出,使用 xp_cmdshell 将模板文件复制到一个新文件中

  • 运行此查询以设置列名(您将使用动态 sql 为您的列创建查询)。将 non=used 列设置为“”(空白)。 HDR=no 意味着您更新所有行,在这种情况下,第一行将是您的标题。

update OPENROWSET('Microsoft.ACE.OLEDB.12.0', 'Excel 12.0; Database=c:\mitz\blank.xlsx; HDR=no', 'Select * from [Sheet1$]')
set F1='mycol1', F2='MYCOL2'
  • 运行此插入查询。 MYCOL1、MYCOL2 也将被动态创建。如果列名需要使用奇怪的名称,请使用 [ ]。
INSERT INTO OPENROWSET('Microsoft.ACE.OLEDB.12.0', 'Excel 12.0; Database=c:\mitz\blank.xlsx', 'Select MYCOL1, MYCOL2 from [Sheet1$]')
SELECT MYCOL1, MYCOL2 from ##some

【讨论】:

  • 如果你想走 bcp 路线,请确保 @query 和 @filepath+@filename 用“”(双引号)括起来,而不是 2 x '(一个接一个的两个单引号)。该命令应在命令提示符下运行。
  • 如果我能让 bcp 路由接受我传递给它的 @query 值,它就会起作用。我用双引号把它包起来,但它仍然不喜欢什么。我在上面粘贴了一份副本。
  • 我 90% 确定你不能将 (char(13) 放入 bcp 查询。我建议将透视数据写入 ##table 然后 bcp "select * from ##mytable" queryout .... 带有 # 的临时表依赖于会话,而 bcp 是另一个会话,因此您需要一个全局临时表(以 ## 开头)。在 BCP 命令完成后删除该表
  • 更清楚一点:像这样运行您的查询: select ... into ##myTable from ... 。然后运行 ​​bcp 命令,例如“select * from ##mytable”。我们每天都使用它来为银行业务生成文本文件。
  • 插入全局临时表解决了 bcp 错误的问题;上面发布了更新。现在我只有 2 个问题需要解决。查询结果中的列标题和逗号与 csv 文件中的列无关。
猜你喜欢
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 2017-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多