【问题标题】:saveDelimitedColumns保存分隔列
【发布时间】:2018-01-31 22:41:16
【问题描述】:

我正在使用存储过程 saveDelimitedColumns(找到:http://www.virtualobjectives.com.au/sqlserver/saving_)将数据结果保存为 .csv 文件。这很好用,但有一个例外......当它保存为 .csv 文件时,excel 中的列标题有括号。例如,[客户 ID],我希望列标题不带括号,作为客户 ID。

下面是 savedelimitedcolumns 存储过程,我不知道是否有办法制作它,所以当它作为 .csv 文件发布时没有括号。

是否可以在下面的代码中进行更改以完成此操作?

谢谢,

ALTER PROCEDURE [dbo].[SaveDelimitedColumns]
@PCWrite varchar(1000) = NULL,
@DBFetch varchar(4000),
@DBWhere varchar(2000) = NULL,
@DBThere varchar(2000) = NULL,
@DBUltra bit = 1,
@Delimiter varchar(100) = 'CHAR(44)', -- Default is ,
@TextQuote varchar(100) = 'CHAR(34)', -- Default is "  Use SPACE(0) for none.
@Header bit = 0, -- Output header. Default is 0.
@NullQuoted bit = 0,
@DateTimeStyle tinyint = 120 -- CONVERT Date Time Style. Default is ODBC canonical yyyy-mm-dd hh:mi:ss(24h)
AS
BEGIN

SET NOCOUNT ON;

DECLARE @Return int
DECLARE @Retain int
DECLARE @Status int

SET @Status = 0

DECLARE @TPre varchar(10)

DECLARE @TDo3 tinyint
DECLARE @TDo4 tinyint

SET @TPre = ''

SET @TDo3 = LEN(@TPre)
SET @TDo4 = LEN(@TPre) + 1

DECLARE @DBAE varchar(40)
DECLARE @Task varchar(6000)
DECLARE @Bank varchar(4000)
DECLARE @Cash varchar(2000)
DECLARE @Risk varchar(2000)
DECLARE @Next varchar(8000)
DECLARE @Save varchar(8000)
DECLARE @Work varchar(8000)
DECLARE @Wish varchar(max)

DECLARE @Name varchar(100)
DECLARE @Same varchar(100)

DECLARE @Rank smallint
DECLARE @Kind varchar(20)
DECLARE @Mask bit
DECLARE @Bond bit
DECLARE @Size int
DECLARE @Wide smallint
DECLARE @More smallint

DECLARE @DBAI varchar(2000)
DECLARE @DBAO varchar(8000)
DECLARE @DBAU varchar(max)

DECLARE @Fuse int
DECLARE @File int

DECLARE @HeaderString varchar(8000)
DECLARE @HeaderDone int

SET @DBAE = '##SaveFile' + RIGHT(CONVERT(varchar(10),@@SPID+100000),5)

SET @Task = 'IF EXISTS (SELECT * FROM tempdb.dbo.sysobjects WHERE name = ' + CHAR(39) + @DBAE + CHAR(39) + ') DROP TABLE ' + @DBAE
EXECUTE (@Task)

SET @Bank = @TPre + @DBFetch

IF NOT EXISTS (SELECT * FROM sysobjects WHERE RTRIM(type) = 'U' AND name = @Bank)
BEGIN
    SET @Bank = CASE WHEN LEFT(LTRIM(@DBFetch),6) = 'SELECT' THEN '(' + @DBFetch + ')' ELSE @DBFetch END
    SET @Bank = REPLACE(@Bank,         CHAR(94),CHAR(39))
    SET @Bank = REPLACE(@Bank,CHAR(45)+CHAR(45),CHAR(32))
    SET @Bank = REPLACE(@Bank,CHAR(47)+CHAR(42),CHAR(32))
END

IF @DBWhere IS NOT NULL
BEGIN
    SET @Cash = REPLACE(@DBWhere,'WHERE'       ,CHAR(32))
    SET @Cash = REPLACE(@Cash,         CHAR(94),CHAR(39))
    SET @Cash = REPLACE(@Cash,CHAR(45)+CHAR(45),CHAR(32))
    SET @Cash = REPLACE(@Cash,CHAR(47)+CHAR(42),CHAR(32))
END

IF @DBThere IS NOT NULL
BEGIN
    SET @Risk = REPLACE(@DBThere,'ORDER BY'    ,CHAR(32))
    SET @Risk = REPLACE(@Risk,         CHAR(94),CHAR(39))
    SET @Risk = REPLACE(@Risk,CHAR(45)+CHAR(45),CHAR(32))
    SET @Risk = REPLACE(@Risk,CHAR(47)+CHAR(42),CHAR(32))
END

SET @DBAI = ''
SET @DBAO = ''
SET @DBAU = ''

SET @Task = 'SELECT * INTO ' + @DBAE + ' FROM ' + @Bank + ' AS T WHERE 0 = 1'
IF @Status = 0 EXECUTE (@Task) SET @Return = @@ERROR
IF @Status = 0 SET @Status = @Return

-- For all columns (Fields) in the table.
DECLARE Fields CURSOR FAST_FORWARD FOR
SELECT '['+C.name+']', C.colid, T.name, C.isnullable, C.iscomputed, C.length, C.prec, C.scale
FROM tempdb.dbo.sysobjects AS O
JOIN tempdb.dbo.syscolumns AS C
  ON O.id = C.id
JOIN tempdb.dbo.systypes AS T
  ON C.xusertype = T.xusertype
WHERE O.name = @DBAE
ORDER BY C.colid

SET @Retain = @@ERROR IF @Status = 0 SET @Status = @Retain

OPEN Fields

SET @Retain = @@ERROR IF @Status = 0 SET @Status = @Retain

FETCH NEXT FROM Fields INTO @Same, @Rank, @Kind, @Mask, @Bond, @Size, @Wide, @More

SET @Retain = @@ERROR IF @Status = 0 SET @Status = @Retain

-- Convert to character for header.
SET @HeaderString = ''
DECLARE @sql nvarchar(4000)
DECLARE @cDelimiter nvarchar(9)
DECLARE @cTextQuote nvarchar(9)
DECLARE @TypeFound bit
SET @sql = N'select @cDelimiter = ' + @Delimiter
EXEC sp_executesql @sql, N'@cDelimiter varchar(9) output', @cDelimiter output
SET @sql = N'select @cTextQuote = ' + @TextQuote
EXEC sp_executesql @sql, N'@cTextQuote varchar(9) output', @cTextQuote output

WHILE @@FETCH_STATUS = 0 AND @Status = 0
BEGIN
    SET @TypeFound = 0

    -- Build header.
    IF LEN(@HeaderString) > 0 SET @HeaderString = @HeaderString + @cDelimiter + ISNULL(@cTextQuote + REPLACE(@Same, @cTextQuote, REPLICATE(@cTextQuote, 2))+@cTextQuote, SPACE(0))
    IF LEN(@HeaderString) = 0 SET @HeaderString = ISNULL(@cTextQuote + REPLACE(@Same, @cTextQuote, REPLICATE(@cTextQuote, 2))+@cTextQuote, SPACE(0))

    IF @Kind IN ('char','nchar','varchar','nvarchar','text','ntext','sysname','xml')
    BEGIN
        IF @NullQuoted = 0
        BEGIN
            IF @Rank = 1 SET @DBAU =                            ' ISNULL('+@TextQuote+'+REPLACE(' + @Same + ','+@TextQuote+',REPLICATE('+@TextQuote+',2))+'+@TextQuote+',SPACE(0))'
            IF @Rank > 1 SET @DBAU = @DBAU + '+' + @Delimiter + '+ISNULL('+@TextQuote+'+REPLACE(' + @Same + ','+@TextQuote+',REPLICATE('+@TextQuote+',2))+'+@TextQuote+',SPACE(0))'
        END
        IF @NullQuoted = 1
        BEGIN
            IF @Rank = 1 SET @DBAU =                            ' ISNULL('+@TextQuote+'+REPLACE(' + @Same + ','+@TextQuote+',REPLICATE('+@TextQuote+',2))+'+@TextQuote+','+@TextQuote+'+'+@TextQuote+')'
            IF @Rank > 1 SET @DBAU = @DBAU + '+' + @Delimiter + '+ISNULL('+@TextQuote+'+REPLACE(' + @Same + ','+@TextQuote+',REPLICATE('+@TextQuote+',2))+'+@TextQuote+','+@TextQuote+'+'+@TextQuote+')'
        END
        SET @TypeFound = 1
    END

    IF @Kind IN ('bit','tinyint','smallint','int','bigint')
    BEGIN
        IF @NullQuoted = 0
        BEGIN
            IF @Rank = 1 SET @DBAU =                            ' ISNULL(CONVERT(varchar(128),' + @Same + '),SPACE(0))'
            IF @Rank > 1 SET @DBAU = @DBAU + '+' + @Delimiter + '+ISNULL(CONVERT(varchar(128),' + @Same + '),SPACE(0))'
        END
        IF @NullQuoted = 1
        BEGIN
            IF @Rank = 1 SET @DBAU =                            ' ISNULL(CONVERT(varchar(128),' + @Same + '),'+@TextQuote+'+'+@TextQuote+')'
            IF @Rank > 1 SET @DBAU = @DBAU + '+' + @Delimiter + '+ISNULL(CONVERT(varchar(128),' + @Same + '),'+@TextQuote+'+'+@TextQuote+')'
        END
        SET @TypeFound = 1
    END

    IF @Kind IN ('numeric','decimal','money','smallmoney','float','real')
    BEGIN
        IF @NullQuoted = 0
        BEGIN
            IF @Rank = 1 SET @DBAU =                            ' ISNULL(CONVERT(varchar(128),' + @Same + '),SPACE(0))'
            IF @Rank > 1 SET @DBAU = @DBAU + '+' + @Delimiter + '+ISNULL(CONVERT(varchar(128),' + @Same + '),SPACE(0))'
        END
        IF @NullQuoted = 1
        BEGIN
            IF @Rank = 1 SET @DBAU =                            ' ISNULL(CONVERT(varchar(128),' + @Same + '),'+@TextQuote+'+'+@TextQuote+')'
            IF @Rank > 1 SET @DBAU = @DBAU + '+' + @Delimiter + '+ISNULL(CONVERT(varchar(128),' + @Same + '),'+@TextQuote+'+'+@TextQuote+')'
        END
        SET @TypeFound = 1
    END

    IF @Kind IN ('uniqueidentifier','geometry','geography')
    BEGIN
        IF @NullQuoted = 0
        BEGIN
            IF @Rank = 1 SET @DBAU =                            ' ISNULL('+@TextQuote+'+CONVERT(varchar(128),' + @Same + ')+'+@TextQuote+',SPACE(0))'
            IF @Rank > 1 SET @DBAU = @DBAU + '+' + @Delimiter + '+ISNULL('+@TextQuote+'+CONVERT(varchar(128),' + @Same + ')+'+@TextQuote+',SPACE(0))'
        END
        IF @NullQuoted = 1
        BEGIN
            IF @Rank = 1 SET @DBAU =                            ' ISNULL('+@TextQuote+'+CONVERT(varchar(128),' + @Same + ')+'+@TextQuote+','+@TextQuote+'+'+@TextQuote+')'
            IF @Rank > 1 SET @DBAU = @DBAU + '+' + @Delimiter + '+ISNULL('+@TextQuote+'+CONVERT(varchar(128),' + @Same + ')+'+@TextQuote+','+@TextQuote+'+'+@TextQuote+')'
        END
        SET @TypeFound = 1
    END

    IF @Kind IN ('datetime2','datetime','smalldatetime','time','date','datetimeoffset')
    BEGIN
        IF @NullQuoted = 0
        BEGIN
            IF @Rank = 1 SET @DBAU =                            ' ISNULL('+@TextQuote+'+CONVERT(varchar(128),' + @Same + ','+convert(varchar(3),@DateTimeStyle)+')+'+@TextQuote+',SPACE(0))'
            IF @Rank > 1 SET @DBAU = @DBAU + '+' + @Delimiter + '+ISNULL('+@TextQuote+'+CONVERT(varchar(128),' + @Same + ','+convert(varchar(3),@DateTimeStyle)+')+'+@TextQuote+',SPACE(0))'
        END
        IF @NullQuoted = 1
        BEGIN
            IF @Rank = 1 SET @DBAU =                            ' ISNULL('+@TextQuote+'+CONVERT(varchar(128),' + @Same + ','+convert(varchar(3),@DateTimeStyle)+')+'+@TextQuote+','+@TextQuote+'+'+@TextQuote+')'
            IF @Rank > 1 SET @DBAU = @DBAU + '+' + @Delimiter + '+ISNULL('+@TextQuote+'+CONVERT(varchar(128),' + @Same + ','+convert(varchar(3),@DateTimeStyle)+')+'+@TextQuote+','+@TextQuote+'+'+@TextQuote+')'
        END
        SET @TypeFound = 1
    END

    IF @TypeFound = 0
    BEGIN
        SET @Retain = 'ERROR: Data type ' + UPPER(@Kind) + ' was used but not supported by SaveDelimitedColumns.'
        SET @Status = @Retain
    END

    FETCH NEXT FROM Fields INTO @Same, @Rank, @Kind, @Mask, @Bond, @Size, @Wide, @More

    SET @Retain = @@ERROR IF @Status = 0 SET @Status = @Retain
END

CLOSE Fields DEALLOCATE Fields

IF LEN(@DBAU) = 0 SET @DBAU = '*'

IF @PCWrite IS NOT NULL AND (@DBUltra = 0) AND (@Header = 1)
BEGIN
    SET @HeaderString = replace(@HeaderString, '"', '""')
    SET @DBAI = ' SELECT ' + CHAR(39) + @HeaderString + CHAR(39) + ' UNION ALL SELECT '
END
ELSE 
    SET @DBAI = ' SELECT '

SET @DBAO = ' FROM ' + @Bank + ' AS T'
    + CASE WHEN @DBWhere IS NULL THEN '' ELSE ' WHERE (' + @Cash + ') AND 0 = 0' END
    + CASE WHEN @DBThere IS NULL THEN '' ELSE ' ORDER BY ' + @Risk END

-- Output where @DBUltra = 0 (Uses XP_CMDSHELL \ BCP)
IF @PCWrite IS NOT NULL AND @DBUltra = 0
BEGIN
    SET @Wish = 'USE ' + DB_NAME() + @DBAI + @DBAU + @DBAO
    SET @Work = 'BCP "' + @Wish + '" QUERYOUT "' + @PCWrite + '" -w -T -S "' + @@SERVERNAME + '" '
    -- PRINT @Work
    EXECUTE @Return = master.dbo.xp_cmdshell @Work, NO_OUTPUT
    SET @Retain = @@ERROR
    IF @Status = 0 SET @Status = @Retain
    IF @Status = 0 SET @Status = @Return

    IF @Status <> 0 GOTO ABORT
END

-- Output where @DBUltra = 1 (Uses Ole Automation)
IF @PCWrite IS NOT NULL AND @DBUltra = 1
BEGIN
    IF @Status = 0 EXECUTE @Return = sp_OACreate 'Scripting.FileSystemObject', @Fuse OUTPUT
    SET @Retain = @@ERROR
    IF @Status = 0 SET @Status = @Retain
    IF @Status = 0 SET @Status = @Return

    IF @Status = 0 EXECUTE @Return = sp_OAMethod @Fuse, 'CreateTextFile', @File OUTPUT, @PCWrite, -1
    SET @Retain = @@ERROR
    IF @Status = 0 SET @Status = @Retain
    IF @Status = 0 SET @Status = @Return

    IF @Status <> 0 GOTO ABORT
END

SET @DBAI = 'DECLARE Records CURSOR GLOBAL FAST_FORWARD FOR' + @DBAI

IF @Status = 0 EXECUTE (@DBAI+@DBAU+@DBAO) SET @Return = @@ERROR
IF @Status = 0 SET @Status = @Return

OPEN Records
SET @Retain = @@ERROR IF @Status = 0 SET @Status = @Retain

FETCH NEXT FROM Records INTO @Next
SET @Retain = @@ERROR IF @Status = 0 SET @Status = @Retain

-- Header.
SET @HeaderDone = 0
WHILE @@FETCH_STATUS = 0 AND @Status = 0
BEGIN
    IF @PCWrite IS NOT NULL AND @DBUltra = 1
    BEGIN
        -- Write header (FILE).
        IF (@Header = 1) and (@HeaderDone = 0)
        BEGIN
            SET @Save = @HeaderString + CHAR(13) + CHAR(10)
            IF @Status = 0 EXECUTE @Return = sp_OAMethod @File, 'Write', NULL, @Save
            SET @HeaderDone = 1
        END

        -- Write the data (FILE).
        SET @Save = @Next + CHAR(13) + CHAR(10)
        IF @Status = 0 EXECUTE @Return = sp_OAMethod @File, 'Write', NULL, @Save
        IF @Status = 0 SET @Status = @Return
    END

    IF @PCWrite IS NULL
    BEGIN
        -- Print header (TEXT).
        IF (@Header = 1) and (@HeaderDone = 0)
        BEGIN
            PRINT @HeaderString + CHAR(13) + CHAR(10)
            SET @HeaderDone = 1
        END
        PRINT @Next
    END

    FETCH NEXT FROM Records INTO @Next
    SET @Retain = @@ERROR IF @Status = 0 SET @Status = @Retain
END

CLOSE Records DEALLOCATE Records

-- Close output file (Ole Automation)
IF @PCWrite IS NOT NULL AND @DBUltra = 1
BEGIN
    EXECUTE @Return = sp_OAMethod @File, 'Close', NULL
    IF @Status = 0 SET @Status = @Return

    EXECUTE @Return = sp_OADestroy @File
    IF @Status = 0 SET @Status = @Return

    EXECUTE @Return = sp_OADestroy @Fuse
    IF @Status = 0 SET @Status = @Return
END

ABORT: -- This label is referenced when OLE automation fails.

IF @Status = 1 OR @Status NOT BETWEEN 0 AND 50000 RAISERROR ('SaveDelimitedColumns Windows Error [%d]', 16, 1, @Status)

SET @Task = 'IF EXISTS (SELECT * FROM tempdb.dbo.sysobjects WHERE name = ' + CHAR(39) + @DBAE + CHAR(39) + ') DROP TABLE ' + @DBAE
EXECUTE (@Task);

RETURN (@Status);

END;

【问题讨论】:

    标签: sql sql-server csv stored-procedures ssms


    【解决方案1】:

    添加行

    SET @HeaderString = replace(@HeaderString, '[', '')
    SET @HeaderString = replace(@HeaderString, ']', '')
    

    就在一行之后

    CLOSE Fields DEALLOCATE Fields
    

    【讨论】:

      【解决方案2】:
      SELECT '['+C.name+']', C.colid, T.name, C.isnullable, C.iscomputed, C.length, C.prec, C.scale
      

      您在列名中添加了 [ ],C.Name 是列名。大多数情况下,您可以避免使用大括号,除非您的表使用保留字作为列名。

      SELECT C.name, C.colid, T.name, C.isnullable, C.iscomputed, C.length, C.prec, C.scale
      

      或者,您可以在 CLOSE 和 DEALOCATE 字段光标之后修剪它们,如下所示:

      CLOSE Fields DEALLOCATE Fields
      SET @HeaderString = replace(replace(@HeaderString, ']', ''), '[', '')
      

      【讨论】:

      • 解决方案 1 不好。它还使用字符串来查询表的列。如果缺少方括号,则可能存在需要转义的列名问题。
      • @nharrer 正如答案中所说 - “大多数时候你可以不使用大括号,除非你的表使用保留字作为列名。”
      • 没错,当我知道我正在使用的表格时,我自己很少使用括号。但是在这样的实用程序代码中,可能会遇到各种表格,添加括号是一种很好的做法。您的第二个解决方案很好,因为它仅用于生成标题行。
      猜你喜欢
      • 2022-12-16
      • 1970-01-01
      • 1970-01-01
      • 2019-05-11
      • 2021-11-17
      • 2019-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多