【问题标题】:Export table to file with column headers (column names) using the bcp utility and SQL Server 2008使用 bcp 实用程序和 SQL Server 2008 将表导出到带有列标题(列名)的文件
【发布时间】:2010-11-24 06:16:15
【问题描述】:

我看到了许多尝试让 bcp 实用程序导出列名以及数据的黑客行为。如果我所做的只是将表转储到文本文件中,让 bcp 添加列标题的最直接方法是什么?

这是我当前使用的 bcp 命令:

bcp myschema.dbo.myTableout myTable.csv /SmyServer01 /c /t, -T

【问题讨论】:

  • 我使用 with 子句和一个虚拟列 OrderCol 来保证顺序。与 temp as ( SELECT 'colName1','colName2','colName3','colName4','colName5','colName6','colName7','colName8',1 OrderCol Union all SELECT col1,col2,col3,col4, col5,col6,col7,col8, 2 OrderCol FROM TableName ) select col1,col2,col3,col4,col5,col6,col7,col8 from Temp order by OrderCol

标签: sql-server csv header bcp


【解决方案1】:

据我所知,BCP 只导出数据 - 我认为没有任何方法可以让它导出带有列名的标题行。

一种常见的解决此问题的技术是使用实际数据的视图进行导出,这基本上是对两个语句执行 UNION ALL:

  • 返回包含列标题的一行的第一条语句
  • 要导出的实际数据

然后在该视图上使用 bcp,而不是直接使用基础数据表。

马克

【讨论】:

  • 不是一个糟糕的解决方案,但这意味着您需要为要导出的每种类型的 .CSV 文件创建一个视图,并在您想更改字段时修改视图和 BCP 命令, 列名等。使用动态 SQL 并将 UNION 作为动态语句的一部分而不是在视图中执行要灵活得多。
【解决方案2】:

除了marc_s的解决方案,还可以使用osqlsqlcmd

这包括标头,它可以像使用 -Q 和 -o 的 bcp 一样工作。但是,它们不支持像 bcp 这样的格式文件。

【讨论】:

    【解决方案3】:

    最简单的方法是使用queryout 选项并使用union all 将列列表与实际表格内容链接

        bcp "select 'col1', 'col2',... union all select * from myschema.dbo.myTableout" queryout myTable.csv /SmyServer01 /c /t, -T
    

    一个例子:

    create table Question1355876
    (id int, name varchar(10), someinfo numeric)
    
    insert into Question1355876
    values (1, 'a', 123.12)
         , (2, 'b', 456.78)
         , (3, 'c', 901.12)
         , (4, 'd', 353.76)
    

    此查询将返回带有标题的信息作为第一行(注意数字值的转换):

    select 'col1', 'col2', 'col3'
    union all
    select cast(id as varchar(10)), name, cast(someinfo as varchar(28))
    from Question1355876
    

    bcp 命令将是:

    bcp "select 'col1', 'col2', 'col3' union all select cast(id as varchar(10)), name, cast(someinfo as varchar(28)) from Question1355876" queryout myTable.csv /SmyServer01 /c /t, -T
    

    【讨论】:

    • 抛出错误:将 varchar 值 'COL001' 转换为数据类型 int 时转换失败。
    • 我添加了一个包含数值的示例。您需要将数字列转换为 varchar(或 nvarchar)
    • Order By 子句失败!
    • order by 完全支持这一点。如果您遇到错误,它必须在您的 sql 语句中。
    • 如果源表中的数据类型为 int,则此方法不起作用
    【解决方案4】:

    此方法使用BCP 自动输出列名和您的行数据。

    脚本为列标题写入一个文件(从INFORMATION_SCHEMA.COLUMNS 表中读取),然后将表数据附加到另一个文件中。

    最终输出组合成TableData.csv,其中包含标题和行数据。只需替换顶部的环境变量以指定服务器、数据库和表名称。

    set BCP_EXPORT_SERVER=put_my_server_name_here
    set BCP_EXPORT_DB=put_my_db_name_here
    set BCP_EXPORT_TABLE=put_my_table_name_here
    
    BCP "DECLARE @colnames VARCHAR(max);SELECT @colnames = COALESCE(@colnames + ',', '') + column_name from %BCP_EXPORT_DB%.INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='%BCP_EXPORT_TABLE%'; select @colnames;" queryout HeadersOnly.csv -c -T -S%BCP_EXPORT_SERVER%
    
    BCP %BCP_EXPORT_DB%.dbo.%BCP_EXPORT_TABLE% out TableDataWithoutHeaders.csv -c -t, -T -S%BCP_EXPORT_SERVER%
    
    set BCP_EXPORT_SERVER=
    set BCP_EXPORT_DB=
    set BCP_EXPORT_TABLE=
    
    copy /b HeadersOnly.csv+TableDataWithoutHeaders.csv TableData.csv
    
    del HeadersOnly.csv
    del TableDataWithoutHeaders.csv
    

    请注意,如果您需要提供凭据,请将 -T 选项替换为 -U my_username -P my_password

    此方法的优点是使用INFORMATION_SCHEMA.COLUMNS 始终使列名与表同步。缺点是它会创建临时文件。 Microsoft 应该真正修复 bcp 实用程序以支持此功能。

    此解决方案使用来自here 的 SQL 行连接技巧结合来自here 的 bcp 想法

    【讨论】:

    • 我使用select substring(@colnames,2,1000000000); 而不是select @colnames;,因为@colnames 变量在标题开头带有逗号。
    • 很棒的脚本老兄。如果可以的话,我会投票两次。有什么方法可以将表和数据库的名称作为批处理脚本变量?
    • @CrazyTim,为了便于使用,我已将名称命名为 env 变量。很高兴它对你有用。
    • 我在尝试时收到此错误:Error = [Microsoft][SQL Native Client]Host-file columns may be skipped only when copying into the Server
    • @thchaver 您使用的是什么版本的 SQL Server?此问题可能与 SQL Server Express 有关。
    【解决方案5】:

    我最近试图弄清楚如何做到这一点,虽然我喜欢顶部最流行的解决方案,但它根本不适合我,因为我需要将名称作为我在脚本中输入的别名,所以我使用了一些批处理文件(在同事的帮助下)来完成自定义表名。

    启动 bcp 的批处理文件在脚本底部有一行,该行执行另一个脚本,该脚本将模板文件与标题名称和刚刚使用以下代码通过 bcp 导出的文件合并。希望这可以帮助遇到我这种情况的其他人。

    echo Add headers from template file to exported sql files....
    Echo School 0031
    copy e:\genin\templates\TEMPLATE_Courses.csv + e:\genin\0031\courses0031.csv e:\genin\finished\courses0031.csv /b
    

    【讨论】:

    • 这是最好的答案。请记住,您不必从批处理文件中执行此操作,您也可以使用“xp_cmdshell”调用复制命令,如果这就是您调用 BCP 的方式。
    【解决方案6】:

    SqlCmd 是一个不错的替代方案,因为它确实包含标头,但它的缺点是在数据周围添加空格填充以提高可读性。您可以将 SqlCmd 与 GnuWin32 sed(流编辑)实用程序结合使用来清理结果。这是一个对我有用的例子,但我不能保证它是防弹的。

    首先,导出数据:

    sqlcmd -S Server -i C:\Temp\Query.sql -o C:\Temp\Results.txt -s"    "
    

    -s" " 是双引号中的制表符。我发现你必须通过批处理文件来运行这个命令,否则 Windows 命令提示符会将选项卡视为自动完成命令,并会用文件名代替选项卡。

    如果 Query.sql 包含:

    SELECT name, object_id, type_desc, create_date
    FROM MSDB.sys.views
    WHERE name LIKE 'sysmail%'
    

    然后您会在 Results.txt 中看到类似的内容

    name                                          object_id   type_desc           create_date            
    -------------------------------------------   ----------- ------------------- -----------------------
    sysmail_allitems                               2001442204 VIEW                2012-07-20 17:38:27.820
    sysmail_sentitems                              2017442261 VIEW                2012-07-20 17:38:27.837
    sysmail_unsentitems                            2033442318 VIEW                2012-07-20 17:38:27.850
    sysmail_faileditems                            2049442375 VIEW                2012-07-20 17:38:27.860
    sysmail_mailattachments                        2097442546 VIEW                2012-07-20 17:38:27.933
    sysmail_event_log                              2129442660 VIEW                2012-07-20 17:38:28.040
    
    (6 rows affected)
    

    接下来,使用 sed 解析文本:

    sed -r "s/ +\t/\t/g" C:\Temp\Results.txt | sed -r "s/\t +/\t/g" | sed -r "s/(^ +| +$)//g" | sed 2d | sed $d | sed "/^$/d" > C:\Temp\Results_New.txt
    

    注意2d是删除第二行,$d是删除最后一行,"/^$/d"是删除空行。

    清理后的文件看起来像这样(虽然我用| 替换了选项卡,所以它们可以在这里可视化):

    name|object_id|type_desc|create_date
    sysmail_allitems|2001442204|VIEW|2012-07-20 17:38:27.820
    sysmail_sentitems|2017442261|VIEW|2012-07-20 17:38:27.837
    sysmail_unsentitems|2033442318|VIEW|2012-07-20 17:38:27.850
    sysmail_faileditems|2049442375|VIEW|2012-07-20 17:38:27.860
    sysmail_mailattachments|2097442546|VIEW|2012-07-20 17:38:27.933
    sysmail_event_log|2129442660|VIEW|2012-07-20 17:38:28.040
    

    【讨论】:

      【解决方案7】:

      我遇到了同样的问题。我需要使用 SQL Server bcp 实用程序导出列标题。这样我就可以一次将包含数据的表“标题”导出到同一个导出文件中。

      声明 @table_name VARCHAR(50) ='mytable' 声明 @columnHeader VARCHAR(8000) SELECT @columnHeader = COALESCE(@columnHeader+',' ,'')+ ''''+column_name +'''' FROM Nal2013.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=@table_name SELECT @raw_sql = 'bcp "SELECT '+ @columnHeader +' UNION ALL SELECT * FROM mytable" queryout c:\datafile.csv -c -t, -T -S '+ @@servername 执行 xp_cmdshell @raw_sql

      编码愉快:)

      【讨论】:

      • 如果数据类型不同怎么办
      • 如果数据类型不同,请将 SELECT 中的任何内容都转换为 VARCHAR,而这些内容还不是 VARCHAR 或 NVARCHAR。由于您无论如何都在写入 .CSV,因此它不会对输出产生任何影响。
      【解决方案8】:

      每个人的版本都有点不同。这是我多年来开发的版本。这个版本似乎解决了我遇到的所有问题。只需将数据集填充到表中,然后将表名传递给此存储过程。

      我这样称呼这个存储过程:

      EXEC    @return_value = *DB_You_Create_The_SP_In*.[dbo].[Export_CSVFile]
              @DB = N'*YourDB*',
              @TABLE_NAME = N'*YourTable*',
              @Dir = N'*YourOutputDirectory*',
              @File = N'*YourOutputFileName*'
      

      还有另外两个变量:

      • @NullBlanks -- 这将采用任何没有值的字段并且 取消它。这很有用,因为在 CSV 的真正意义上 规范每个数据点应该有引号。如果你 拥有大量数据集,这将为您节省大量空间 在这些字段中没有“”(两个双引号)。如果您觉得这没有用,请将其设置为 0。
      • @IncludeHeaders -- 我有一个用于输出 CSV 的存储过程 文件,所以如果我不想要标题,我确实有那个标志。

      这将创建存储过程:

      CREATE PROCEDURE [dbo].[Export_CSVFile] 
      (@DB varchar(128),@TABLE_NAME varchar(128), @Dir varchar(255), @File varchar(250),@NULLBLANKS bit=1,@IncludeHeader bit=1)
      AS
      
      DECLARE @CSVHeader varchar(max)=''  --CSV Header
      , @CmdExc varchar(8000)=''          --EXEC commands
      , @SQL varchar(max)=''              --SQL Statements
      , @COLUMN_NAME varchar(128)=''      --Column Names
      , @DATA_TYPE varchar(15)=''         --Data Types
      
      DECLARE @T table (COLUMN_NAME varchar(128),DATA_TYPE varchar(15))
      
      --BEGIN Ensure Dir variable has a backslash as the final character
      IF NOT RIGHT(@Dir,1) = '\' BEGIN SET @Dir=@Dir+'\' END
      --END
      
      --BEGIN Drop TEMP Table IF Exists
      SET @SQL='IF (EXISTS (SELECT * FROM '+@DB+'.INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''TEMP_'+@TABLE_NAME+''')) BEGIN EXEC(''DROP TABLE ['+@DB+'].[dbo].[TEMP_'+@TABLE_NAME+']'') END'
      EXEC(@SQL)
      --END
      
      SET @SQL='SELECT COLUMN_NAME,DATA_TYPE FROM '+@DB+'.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME ='''+@TABLE_NAME+''' ORDER BY ORDINAL_POSITION'
      INSERT INTO @T
      EXEC (@SQL)
      
      SET @SQL=''
      WHILE exists(SELECT * FROM @T)
          BEGIN
              SELECT top(1) @DATA_TYPE=DATA_TYPE,@COLUMN_NAME=COLUMN_NAME FROM @T
              IF @DATA_TYPE LIKE '%char%' OR @DATA_TYPE LIKE '%text'
                  BEGIN 
                  IF @NULLBLANKS = 1
                      BEGIN
                          SET @SQL+='CASE PATINDEX(''%[0-9,a-z]%'','+@COLUMN_NAME+') WHEN ''0'' THEN NULL ELSE ''"''+RTRIM(LTRIM('+@COLUMN_NAME+'))+''"'' END AS ['+@COLUMN_NAME+'],' 
                      END
                  ELSE
                      BEGIN
                          SET @SQL+='''"''+RTRIM(LTRIM('+@COLUMN_NAME+'))+''"'' AS ['+@COLUMN_NAME+'],' 
                      END
                  END
              ELSE
                  BEGIN SET @SQL+=@COLUMN_NAME+',' END
                  SET @CSVHeader+='"'+@COLUMN_NAME+'",'
                  DELETE top(1) @T
          END 
      
      IF LEN(@CSVHeader)>1 BEGIN SET @CSVHeader=RTRIM(LTRIM(LEFT(@CSVHeader,LEN(@CSVHeader)-1))) END
      
      IF LEN(@SQL)>1 BEGIN SET @SQL= 'SELECT '+ LEFT(@SQL,LEN(@SQL)-1) + ' INTO ['+@DB+'].[dbo].[TEMP_'+@TABLE_NAME+'] FROM ['+@DB+'].[dbo].['+@TABLE_NAME+']' END
      EXEC(@SQL)
      
      IF @IncludeHeader=0 
          BEGIN
              --BEGIN Create Data file
              SET  @CmdExc ='BCP "'+@DB+'.dbo.TEMP_'+@TABLE_NAME+'" out "'+@Dir+'Data_'+@TABLE_NAME+'.csv" /c /t, -T' 
              EXEC master..xp_cmdshell @CmdExc
              --END
              SET  @CmdExc ='del '+@Dir+@File EXEC master..xp_cmdshell @CmdExc
              SET  @CmdExc ='ren '+@Dir+'Data_'+@TABLE_NAME+'.csv '+@File EXEC master..xp_cmdshell @CmdExc
          END 
      else
          BEGIN
      
              --BEGIN Create Header and main file
              SET  @CmdExc ='echo '+@CSVHeader+'> '+@Dir+@File EXEC master..xp_cmdshell @CmdExc
              --END
      
              --BEGIN Create Data file
              SET  @CmdExc ='BCP "'+@DB+'.dbo.TEMP_'+@TABLE_NAME+'" out "'+@Dir+'Data_'+@TABLE_NAME+'.csv" /c /t, -T' 
              EXEC master..xp_cmdshell @CmdExc
              --END
      
              --BEGIN Merge Data File With Header File
              SET @CmdExc = 'TYPE '+@Dir+'Data_'+@TABLE_NAME+'.csv >> '+@Dir+@File EXEC master..xp_cmdshell @CmdExc
              --END
      
              --BEGIN Delete Data File
              SET @CmdExc = 'DEL /q '+@Dir+'Data_'+@TABLE_NAME+'.csv' EXEC master..xp_cmdshell @CmdExc
              --END
          END
      --BEGIN Drop TEMP Table IF Exists
      SET @SQL='IF (EXISTS (SELECT * FROM '+@DB+'.INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''TEMP_'+@TABLE_NAME+''')) BEGIN EXEC(''DROP TABLE ['+@DB+'].[dbo].[TEMP_'+@TABLE_NAME+']'') END'
      EXEC(@SQL)
      

      【讨论】:

      • 不错。谢谢!使用“@CmdExc varchar(max)”时出现这些错误:过程需要“varchar”类型的参数“command_string”。所以从最大值更改为 8000 并且它可以工作
      【解决方案9】:

      我已经用下面的代码成功地实现了这一点。 将以下代码放入 SQL Server 新查询窗口并尝试:

      CREATE TABLE tempDBTableDetails ( TableName VARCHAR(500), [RowCount] VARCHAR(500), TotalSpaceKB VARCHAR(500),
                      UsedSpaceKB VARCHAR(500), UnusedSpaceKB VARCHAR(500) )
      
          -- STEP 1 ::
          DECLARE @cmd VARCHAR(4000)
      
      INSERT INTO tempDBTableDetails
      SELECT 'TableName', 'RowCount', 'TotalSpaceKB', 'UsedSpaceKB', 'UnusedSpaceKB'
      INSERT INTO tempDBTableDetails
      SELECT
          S.name +'.'+ T.name as TableName,
          Convert(varchar,Cast(SUM(P.rows) as Money),1) as [RowCount],
          Convert(varchar,Cast(SUM(a.total_pages) * 8 as Money),1) AS TotalSpaceKB,
          Convert(varchar,Cast(SUM(a.used_pages) * 8 as Money),1) AS UsedSpaceKB,
          (SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB
      FROM sys.tables T
      INNER JOIN sys.partitions P ON P.OBJECT_ID = T.OBJECT_ID
      INNER JOIN sys.schemas S ON T.schema_id = S.schema_id
      INNER JOIN sys.allocation_units A ON p.partition_id = a.container_id
      WHERE T.is_ms_shipped = 0 AND P.index_id IN (1,0)
      GROUP BY S.name, T.name
      ORDER BY SUM(P.rows) DESC
      
      -- SELECT * FROM [FIINFRA-DB-SIT].dbo.tempDBTableDetails ORDER BY LEN([RowCount]) DESC
      
      SET @cmd = 'bcp "SELECT * FROM [FIINFRA-DB-SIT].dbo.tempDBTableDetails ORDER BY LEN([RowCount]) DESC" queryout "D:\Milind\export.xls" -U sa -P dbowner -c'
          Exec xp_cmdshell @cmd
      
      --DECLARE @HeaderCmd VARCHAR(4000)
      --SET @HeaderCmd = 'SELECT ''TableName'', ''RowCount'', ''TotalSpaceKB'', ''UsedSpaceKB'', ''UnusedSpaceKB'''
      exec master..xp_cmdshell 'BCP "SELECT ''TableName'', ''RowCount'', ''TotalSpaceKB'', ''UsedSpaceKB'', ''UnusedSpaceKB''" queryout "d:\milind\header.xls" -U sa -P dbowner -c'
      exec master..xp_cmdshell 'copy /b "d:\Milind\header.xls"+"d:\Milind\export.xls" "d:/Milind/result.xls"'
      
      exec master..xp_cmdshell 'del "d:\Milind\header.xls"'
      exec master..xp_cmdshell 'del "d:\Milind\export.xls"'
      
      DROP TABLE tempDBTableDetails
      

      【讨论】:

        【解决方案10】:

        您应该能够使用一个 cte 视图和一个包含 bcp 代码的批处理文件来解决这个问题。首先创建视图。因为它相对简单,所以我没有创建临时表。通常我会这样做

        CREATE VIEW [dbo].[vwxMySAMPLE_EXTRACT_COLUMNS]
          AS
            WITH MYBCP_CTE (COLUMN_NM, ORD_POS, TXT)
             AS
              ( SELECT  COLUMN_NAME
                     , ORDINAL_POSITION
                     , CAST(COLUMN_NAME AS VARCHAR(MAX))
                FROM [INFORMATION_SCHEMA].[COLUMNS]
                WHERE TABLE_NAME = 'xMySAMPLE_EXTRACT_NEW'
                AND ORDINAL_POSITION = 1
        
                UNION ALL
        
                SELECT  V.COLUMN_NAME
                      , V.ORDINAL_POSITION
                      , CAST(C.TXT + '|' + V.COLUMN_NAME AS VARCHAR(MAX))
                FROM [INFORMATION_SCHEMA].[COLUMNS]  V INNER JOIN MYBCP_CTE C
                ON V.ORDINAL_POSITION = C.ORD_POS+1
                AND V.ORDINAL_POSITION > 1
                WHERE TABLE_NAME = 'xMySAMPLE_EXTRACT_NEW'
              )
        
              SELECT CC.TXT
              FROM MYBCP_CTE CC INNER JOIN ( SELECT MAX(ORD_POS) AS MX_CNT
                                             FROM MYBCP_CTE C
                                            ) SC
              ON CC.ORD_POS = SC.MX_CNT
        

        现在,创建批处理文件。我在我的 Temp 目录中创建了这个,但我很懒。

          cd\
          CD "C:\Program Files\Microsoft SQL Server\110\Tools\Binn"
        
          set buildhour=%time: =0%
          set buildDate=%DATE:~4,10%
          set backupfiledate=%buildDate:~6,4%%buildDate:~0,2%%buildDate:~3,2%%time:~0,2%%time:~3,2%%time:~6,2%
        
          echo %backupfiledate%
          pause
        

        上面的代码只是创建了一个附加到文件末尾的日期...接下来,第一个 bcp 语句带有递归 cte 的视图,将它们连接在一起。

          bcp "SELECT *  FROM [dbo].[vwxMYSAMPLE_EXTRACT_COLUMNS] OPTION (MAXRECURSION 300)" queryout C:\Temp\Col_NM%backupfiledate%.txt -c -t"|" -S MYSERVERTOLOGINTO -T -q
          bcp "SELECT *  FROM [myDBName].[dbo].[vwxMYSAMPLE_EXTRACT_NEW] " queryout C:\Temp\3316_PHYSDATA_ALL%backupfiledate%.txt -c -t"|" -S MYSERVERTOLOGINTO -T -q
        

        现在使用复制命令将它们合并在一起:

          copy C:\Temp\Col_NM%backupfiledate%.txt  + C:\Temp\3316_PHYSDATA_ALL%backupfiledate%.txt  C:\Temp\3316_PHYSDATA_ALL%backupfiledate%.csv
        

        一切准备就绪

        【讨论】:

          【解决方案11】:

          这是一个非常简单的存储过程,也可以解决问题...

              CREATE PROCEDURE GetBCPTable
              @table_name varchar(200)
          AS
          BEGIN
              DECLARE @raw_sql nvarchar(3000)
          
              DECLARE @columnHeader VARCHAR(8000)
              SELECT @columnHeader = COALESCE(@columnHeader+',' ,'')+ ''''+column_name +'''' FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @table_name
          
              DECLARE @ColumnList VARCHAR(8000)
              SELECT @ColumnList = COALESCE(@ColumnList+',' ,'')+ 'CAST('+column_name +' AS VARCHAR)' FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @table_name
          
              SELECT @raw_sql = 'SELECT '+ @columnHeader +' UNION ALL SELECT ' + @ColumnList + ' FROM ' + @table_name
              --PRINT @raw_SQL
              EXECUTE sp_executesql  @raw_sql
          END
          GO
          

          【讨论】:

            【解决方案12】:

            最新版sqlcmd新增-w选项,去掉字段值后多余的空格;但是,它不会在字符串周围加上引号,这可能是CSV 文件在导入包含逗号的字段值时出现的问题。

            【讨论】:

              【解决方案13】:

              请在下面找到制作同样东西的另一种方法。

              此过程还接受架构名称作为参数,以防您需要它来访问您的表。

              CREATE PROCEDURE Export_Data_NBA
              @TableName nchar(50),
              @TableSchema nvarchar(50) = ''
              
              AS
              DECLARE @TableToBeExported as nvarchar(50);
              
              DECLARE @OUTPUT TABLE (col1 nvarchar(max));
              DECLARE @colnamestable VARCHAR(max);
              select @colnamestable = COALESCE(@colnamestable, '') +COLUMN_NAME+ ','
              from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @TableName
              order BY ORDINAL_POSITION
              
              SELECT @colnamestable = LEFT(@colnamestable,DATALENGTH(@colnamestable)-1)
              
              INSERT INTO @OUTPUT
              select @colnamestable
              
              DECLARE @selectstatement VARCHAR(max);
              select @selectstatement = COALESCE(@selectstatement, '') + 'Convert(nvarchar(100),'+COLUMN_NAME+')+'',''+'
              from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @TableName
              order BY ORDINAL_POSITION
              
              SELECT @selectstatement = LEFT(@selectstatement,DATALENGTH(@selectstatement)-1)
              
              DECLARE @sqlstatment as nvarchar(max);
              
              SET @TableToBeExported = @TableSchema+'.'+@TableToBeExported
              
              SELECT @sqlstatment = N'Select '+@selectstatement+N' from '+@TableToBeExported
              
              INSERT INTO @OUTPUT
              exec sp_executesql @stmt = @sqlstatment
              
              SELECT * from @OUTPUT
              

              【讨论】:

                【解决方案14】:

                我得到了一个基于我之前看到的版本。将导出文件创建为 CSV 或 TXT 对我有很大帮助。我将表存储到## 临时表中:

                    IF OBJECT_ID('tempdb..##TmpExportFile') IS NOT NULL
                DROP TABLE ##TmpExportFile;
                
                
                DECLARE @columnHeader VARCHAR(8000)
                DECLARE @raw_sql nvarchar(3000)
                
                SELECT
                              * INTO ##TmpExportFile
                              ------ FROM THE TABLE RESULTS YOU WANT TO GET
                              ------ COULD BE A TABLE OR A TEMP TABLE BASED ON INNER JOINS
                              ------ ,ETC.
                
                FROM TableName -- optional WHERE ....
                
                
                DECLARE @table_name  VARCHAR(50) = '##TmpExportFile'
                SELECT
                              @columnHeader = COALESCE(@columnHeader + ',', '') + '''[' + c.name + ']''' + ' as ' + '' + c.name + ''
                FROM tempdb.sys.columns c
                INNER JOIN tempdb.sys.tables t
                              ON c.object_id = t.object_id
                WHERE t.NAME = @table_name
                
                print @columnheader
                
                                DECLARE @ColumnList VARCHAR(max)
                SELECT
                              @ColumnList = COALESCE(@ColumnList + ',', '') + 'CAST([' + c.name + '] AS CHAR(' + LTRIM(STR(max_length)) + '))'
                FROM tempdb.sys.columns c
                INNER JOIN tempdb.sys.tables t
                              ON c.object_id = t.object_id
                WHERE t.name = @table_name
                print @ColumnList
                
                --- CSV FORMAT                                       
                SELECT
                              @raw_sql = 'bcp "SELECT ' + @columnHeader + ' UNION all SELECT ' + @ColumnList + ' FROM ' + @table_name + ' " queryout \\networkdrive\networkfolder\datafile.csv -c -t, /S' + ' SQLserverName /T'
                --PRINT @raw_sql
                EXEC xp_cmdshell @raw_sql
                
                  --- TXT FORMAT
                       SET @raw_sql = 'bcp "SELECT ' + @columnHeader + ' UNION all SELECT ' + @ColumnList + ' FROM ' + @table_name + ' " queryout \\networkdrive\networkfolder\MISD\datafile.txt /c /S'+ ' SQLserverName /T'
                       EXEC xp_cmdshell @raw_sql
                
                
                
                DROP TABLE ##TmpExportFile
                

                【讨论】:

                  【解决方案15】:

                  使用一个小的 PowerShell 脚本:

                  sqlcmd -Q "set nocount on select top 0 * from [DB].[schema].[table]" -o c:\temp\header.txt
                  bcp [DB].[schema].[table] out c:\temp\query.txt -c -T -S BRIZA
                  Get-Content c:\temp\*.txt | Set-Content c:\temp\result.txt
                  Remove-Item c:\temp\header.txt
                  Remove-Item c:\temp\query.txt

                  警告:连接遵循 .txt 文件名(按字母顺序)

                  【讨论】:

                    【解决方案16】:

                    这里的一些解决方案过于复杂。这是一个有 4 行代码,没有批处理文件,没有外部应用程序,并且全部自包含在 SQL 服务器中。

                    在此示例中,我的表名为“MyTable”,它有两列名为 Column1 和 Column2。 Column2 是一个整数,因此我们需要将其转换为 varchar 以进行导出:

                    DECLARE @FileName varchar(100)
                    DECLARE @BCPCommand varchar(8000)
                    DECLARE @ColumnHeader varchar(8000)
                    
                        SET @FileName = 'C:\Temp\OutputFile.csv'
                     SELECT @ColumnHeader = COALESCE(@ColumnHeader+',' ,'')+ ''''+column_name +'''' FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='MyTable'
                        SET @BCPCommand = 'bcp "SELECT '+ @ColumnHeader +' UNION ALL SELECT Column1, CAST(Column2 AS varchar(100)) AS Column2 FROM MyTable" queryout "' + @FileName + '" -c -t , -r \n  -S . -T'
                       EXEC master..xp_cmdshell @BCPCommand
                    

                    您可以将此添加到存储过程中,以完全自动化您的 .CSV 文件(带有标题行)的创建。

                    【讨论】:

                      【解决方案17】:
                      DECLARE @table_name varchar(max)='tableName'--which needs to be exported
                      DECLARE @fileName varchar(max)='file Name'--What would be file name
                      
                      DECLARE @query varchar(8000)
                      DECLARE @columnHeader VARCHAR(max)
                      SELECT @columnHeader = COALESCE(@columnHeader+',' ,'')+ ''''+column_name +''''  FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @table_name
                      
                      DECLARE @ColumnList VARCHAR(max)
                      SELECT @ColumnList = COALESCE(@ColumnList+',' ,'')+ 'CAST('+column_name +' AS VARCHAR)' +column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @table_name
                      
                      DECLARE @tempRaw_sql nvarchar(max)
                      SELECT @tempRaw_sql = 'SELECT ' + @ColumnList + ' into ##temp11 FROM ' + @table_name 
                      PRINT @tempRaw_sql
                      EXECUTE sp_executesql  @tempRaw_sql
                      
                      
                      DECLARE @raw_sql nvarchar(max)
                      SELECT @raw_sql = 'SELECT  '+ @columnHeader +' UNION ALL SELECT * FROM ##temp11'
                      PRINT @raw_SQL
                      SET @query='bcp "'+@raw_SQL+'" queryout "C:\data\'+@fileName+'.txt" -T -c -t,'
                      EXEC xp_cmdshell @query
                      
                      
                      DROP TABLE ##temp11
                      

                      【讨论】:

                      • 解释一下。
                      【解决方案18】:

                      为:

                      • Windows,64 位
                      • SQL Server(使用SQL Server 2017 测试,应该适用于所有版本):

                      选项 1:命令提示符

                      sqlcmd -s, -W -Q "set nocount on; select * from [DATABASE].[dbo].[TABLENAME]" | findstr /v /c:"-" /b > "c:\dirname\file.csv"
                      

                      地点:

                      • [DATABASE].[dbo].[TABLENAME] 是要写的表。
                      • c:\dirname\file.csv 是要写入的文件(用引号括起来以处理带空格的路径)。
                      • 输出 .csv 文件包括标题。

                      注意:我倾向于避免使用 bcp:它是遗留的,它比 sqlcmd 早了十年,而且它似乎永远不会在不引起一大堆头痛的情况下工作。

                      选项 2:在 SQL 脚本中

                      -- Export table [DATABASE].[dbo].[TABLENAME] to .csv file c:\dirname\file.csv
                      exec master..xp_cmdshell 'sqlcmd -s, -W -Q "set nocount on; select * from [DATABASE].[dbo].[TABLENAME]" | findstr /v /c:"-" /b > "c:\dirname\file.csv"'
                      

                      疑难解答:必须在 MSSQL 中 enable xp_cmdshell

                      样本输出

                      文件:file.csv

                      ID,Name,Height
                      1,Bob,192
                      2,Jane,184
                      3,Harry,186
                      

                      速度

                      理论上尽可能快:与bcp 相同的速度,比从 SSMS 手动导出快很多倍。

                      参数说明(可选-可以忽略)

                      sqlcmd:

                      • -s, 在每列之间放置一个逗号。
                      • -W 消除了值两侧的填充。
                      • set nocount on 在查询结束时消除垃圾行。

                      对于findstr

                      • 所有这些都是删除标题下方的第二行下划线,例如--- ----- ---- ---- ----- --
                      • /v /c:"-" 匹配任何以“-”开头的行。
                      • /b 返回所有其他行。

                      导入其他程序

                      在 Excel 中:

                      • 可以直接在 Excel 中打开文件。

                      在 Python 中:

                      import pandas as pd
                      df_raw = pd.read_csv("c:\dirname\file.csv")
                      

                      【讨论】:

                      • 这很棒。我特别喜欢它是如何运行导出的单行 SQL。我可能会开始使用它而不是 bcp。唯一需要注意的是,如果您在第 1 列中的任何值以“-”开头,它们将从导出中删除。将负数转换为 varchar 可能会变得混乱。
                      • 这很棒。帮了我很多。谢谢
                      猜你喜欢
                      • 2021-05-29
                      • 2014-05-30
                      • 2012-08-21
                      • 1970-01-01
                      • 1970-01-01
                      • 2022-12-18
                      • 1970-01-01
                      • 2020-04-06
                      • 1970-01-01
                      相关资源
                      最近更新 更多