【问题标题】:How to produce an csv output file from stored procedure in SQL Server如何从 SQL Server 中的存储过程生成 csv 输出文件
【发布时间】:2013-04-18 09:48:41
【问题描述】:

是否可以从 SQL Server 中的存储过程生成 csv 文件?我创建了存储过程,我想将一些结果存储为 csv,有人知道如何实现吗?

【问题讨论】:

  • 除了下面的答案,我会考虑你是否真的想从过程中生成 csv 文件。第一个问题是权限:SQL Server 服务帐户需要写入输出文件夹的权限,这可能会导致问题。第二个问题是,通常最好将获取数据与格式化/呈现数据分开。让程序生成结果,然后使用外部脚本生成 csv 文件。这样,您可以对过程的结果执行许多不同的操作,生成 csv 文件不是“硬编码”的。

标签: sql sql-server stored-procedures


【解决方案1】:

我认为可以使用 bcp 命令。我也是这个命令的新手,但我关注了this link,它对我有用。

【讨论】:

    【解决方案2】:

    此脚本在任何表结构的输出窗口中将指定表中的行导出为 CSV 格式。希望该脚本对您有所帮助-

    DECLARE 
          @TableName SYSNAME
        , @ObjectID INT
    
    DECLARE [tables] CURSOR READ_ONLY FAST_FORWARD LOCAL FOR 
        SELECT 
              '[' + s.name + '].[' + t.name + ']'
            , t.[object_id]
        FROM (
            SELECT DISTINCT
                  t.[schema_id]
                , t.[object_id]
                , t.name
            FROM sys.objects t WITH (NOWAIT)
            JOIN sys.partitions p WITH (NOWAIT) ON p.[object_id] = t.[object_id]
            WHERE p.[rows] > 0
                AND t.[type] = 'U'
        ) t
        JOIN sys.schemas s WITH (NOWAIT) ON t.[schema_id] = s.[schema_id]
        WHERE t.name IN ('<your table name>')
    
    OPEN [tables]
    
    FETCH NEXT FROM [tables] INTO 
          @TableName
        , @ObjectID
    
    DECLARE 
          @SQLInsert NVARCHAR(MAX)
        , @SQLColumns NVARCHAR(MAX)
        , @SQLTinyColumns NVARCHAR(MAX)
    
    WHILE @@FETCH_STATUS = 0 BEGIN
    
        SELECT 
              @SQLInsert = ''
            , @SQLColumns = ''
            , @SQLTinyColumns = ''
    
        ;WITH cols AS 
        (
            SELECT 
                  c.name
                , datetype = t.name
                , c.column_id
            FROM sys.columns c WITH (NOWAIT)
            JOIN sys.types t WITH (NOWAIT) ON c.system_type_id = t.system_type_id AND c.user_type_id = t.user_type_id
            WHERE c.[object_id] = @ObjectID
                AND c.is_computed = 0
                AND t.name NOT IN ('xml', 'geography', 'geometry', 'hierarchyid')
        )
        SELECT 
              @SQLTinyColumns = STUFF((
                SELECT ', [' + c.name + ']'
                FROM cols c
                ORDER BY c.column_id
                FOR XML PATH, TYPE, ROOT).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
            , @SQLColumns = STUFF((SELECT CHAR(13) +
                CASE 
                    WHEN c.datetype = 'uniqueidentifier' 
                        THEN ' + '';'' + ISNULL('''' + CAST([' + c.name + '] AS VARCHAR(MAX)) + '''', ''NULL'')' 
                    WHEN c.datetype IN ('nvarchar', 'varchar', 'nchar', 'char', 'varbinary', 'binary') 
                        THEN ' + '';'' + ISNULL('''' + CAST(REPLACE([' + c.name + '], '''', '''''''') AS NVARCHAR(MAX)) + '''', ''NULL'')' 
                    WHEN c.datetype = 'datetime'
                        THEN ' + '';'' + ISNULL('''' + CONVERT(VARCHAR, [' + c.name + '], 120) + '''', ''NULL'')' 
                    ELSE 
                    ' + '';'' + ISNULL(CAST([' + c.name + '] AS NVARCHAR(MAX)), ''NULL'')'
                END
                FROM cols c
                ORDER BY c.column_id
                FOR XML PATH, TYPE, ROOT).value('.', 'NVARCHAR(MAX)'), 1, 10, 'CHAR(13) + '''' +')
    
        DECLARE @SQL NVARCHAR(MAX) = '    
        SET NOCOUNT ON;
        DECLARE 
              @SQL NVARCHAR(MAX) = ''''
            , @x INT = 1
            , @count INT = (SELECT COUNT(1) FROM ' + @TableName + ')
    
        IF EXISTS(
            SELECT 1
            FROM tempdb.dbo.sysobjects
            WHERE ID = OBJECT_ID(''tempdb..#import'')
        )
            DROP TABLE #import;
    
        SELECT ' + @SQLTinyColumns + ', ''RowNumber'' = ROW_NUMBER() OVER (ORDER BY ' + @SQLTinyColumns + ')
        INTO #import
        FROM ' + @TableName + ' 
    
        WHILE @x < @count BEGIN
    
            SELECT @SQL = STUFF((
            SELECT ' + @SQLColumns + ' + ''''' + '
            FROM #import 
            WHERE RowNumber BETWEEN @x AND @x + 9
            FOR XML PATH, TYPE, ROOT).value(''.'', ''NVARCHAR(MAX)''), 1, 1, '''')
    
            PRINT(@SQL)
    
            SELECT @x = @x + 10
    
        END'
    
        EXEC sys.sp_executesql @SQL
    
        FETCH NEXT FROM [tables] INTO 
              @TableName
            , @ObjectID
    
    END
    
    CLOSE [tables]
    DEALLOCATE [tables]
    

    在输出窗口中,您会看到类似这样的内容 (AdventureWorks.Person.Person):

    1;EM;0;NULL;Ken;J;Sánchez;NULL;0;92C4279F-1207-48A3-8448-4636514EB7E2;2003-02-08 00:00:00
    2;EM;0;NULL;Terri;Lee;Duffy;NULL;1;D8763459-8AA8-47CC-AFF7-C9079AF79033;2002-02-24 00:00:00
    3;EM;0;NULL;Roberto;NULL;Tamburello;NULL;0;E1A2555E-0828-434B-A33B-6F38136A37DE;2001-12-05 00:00:00
    4;EM;0;NULL;Rob;NULL;Walters;NULL;0;F2D7CE06-38B3-4357-805B-F4B6B71C01FF;2001-12-29 00:00:00
    5;EM;0;Ms.;Gail;A;Erickson;NULL;0;F3A3F6B4-AE3B-430C-A754-9F2231BA6FEF;2002-01-30 00:00:00
    6;EM;0;Mr.;Jossef;H;Goldberg;NULL;0;0DEA28FD-EFFE-482A-AFD3-B7E8F199D56F;2002-02-17 00:00:00
    

    【讨论】:

      【解决方案3】:

      您可以按照answer 中的建议使用 OPENROWSET 执行此操作。转发Slogmeister Extrarodinare答案:

      使用 T-SQL

      INSERT INTO OPENROWSET ('Microsoft.ACE.OLEDB.12.0','Text;Database=D:\;HDR=YES;FMT=Delimited','SELECT * FROM [FileName.csv]')
      SELECT Field1, Field2, Field3 FROM DatabaseName
      

      但是,有几点需要注意:

      1. 您需要有可用的 Microsoft.ACE.OLEDB.12.0 提供程序。 Jet 4.0 提供程序也可以工作,但它很古老,所以我改用了这个。

      2. .CSV 文件必须已经存在。如果您使用标题 (HDR=YES),请确保 .CSV 文件的第一行是所有字段的分隔列表。

      【讨论】:

        【解决方案4】:

        找到了一个非常有用的链接。为此使用 SQLCMD 确实比使用存储过程解决此问题要容易

        http://www.excel-sql-server.com/sql-server-export-to-excel-using-bcp-sqlcmd-csv.htm

        【讨论】:

          【解决方案5】:

          我还使用了 bcp 并发现了一些其他有用的帖子,如果找到这个帖子,这些帖子会让其他人受益

          不要使用 VARCHAR(MAX) 作为 xp_cmdshell 的 @sql@cmd 变量;你会得到错误

          消息 214,级别 16,状态 201,过程 xp_cmdshell,第 1 行过程 需要“varchar”类型的参数“command_string”。

          http://www.sqlservercentral.com/Forums/Topic1071530-338-1.aspx

          使用NULLIF 代替NUL(可在十六进制编辑器或记事本++ 中查看)来获取csv 文件的空白。我在 bcp 的 SELECT 语句中使用了它

          How to make Microsoft BCP export empty string instead of a NUL char?

          【讨论】:

          • 不要使用 VARCHAR(MAX)... 好的.. 但是我用什么?
          【解决方案6】:

          我已经尝试过了,对我来说效果很好:

          sqlcmd -S servername -E -s~ -W -k1 -Q  "sql query here" > "\\file_path\file_name.csv"
          

          【讨论】:

            【解决方案7】:

            只是为了回答最终可行的本地方法,所有内容都必须转换为 varchar

            ALTER PROCEDURE [clickpay].[sp_GetDocuments] 
            
            @Submid bigint
            
            AS
            BEGIN
            -- SET NOCOUNT ON added to prevent extra result sets from
            -- interfering with SELECT statements.
            SET NOCOUNT ON;
               DECLARE @raw_sql varchar(max)
            
            DECLARE @columnHeader VARCHAR(max)
            SELECT @columnHeader = COALESCE(@columnHeader+',' ,'')+ ''''+column_name +'''' FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'Documents'
            
            DECLARE @ColumnList VARCHAR(max)
            SELECT @ColumnList = COALESCE(@ColumnList+',' ,'')+ 'CAST('+column_name +' AS VARCHAR)' FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'Documents'
            
            SELECT @raw_sql = 'SELECT '+ @columnHeader +' UNION ALL SELECT ' + @ColumnList + ' FROM ' + 'Documents where Submid = ' +  CAST(@Submid AS VARCHAR)
            
            -- Insert statements for procedure here
            exec(@raw_sql)
            END
            

            【讨论】:

            • 请在“END”前放置 4 个空格,以便将其包含在代码块中。编辑至少需要 6 个字符,因此我无法为您完成。
            猜你喜欢
            • 1970-01-01
            • 2019-06-11
            • 1970-01-01
            • 2012-07-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-02-02
            相关资源
            最近更新 更多