首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >是否从SQL中的连接尾部记录中删除回车符和换行符?

是否从SQL中的连接尾部记录中删除回车符和换行符?
EN

Stack Overflow用户
提问于 2019-06-06 23:33:41
回答 3查看 1.3K关注 0票数 2

我有一个在SSMS中运行的SQL查询的结果数据集,其中包括一个以.txt格式导出并保存到记事本的单行尾部记录。但是,尾部记录会自动包括十六进制控制,以便在作为尾部记录的连接字段(750个字符)之后包含换行符/回车符记录。在导出为.txt格式之前,如何从尾部记录的末尾消除此错误?文件不能包含任何空行。

对于我的尾部记录,我在SELECT语句中尝试了以下代码,这似乎是解决这种情况的常见方法:

代码语言:javascript
运行
复制
REPLACE(REPLACE('T'+CAST(RIGHT(REPLACE(STR(COUNT(*)),' ','0'),9) AS VARCHAR)+SPACE(740),CHAR(10),''),CHAR(13),'')

但是,在以.txt格式导出时,它仍然包含换行符和回车符。

代码语言:javascript
运行
复制
REPLACE(REPLACE('T'+CAST(RIGHT(REPLACE(STR(COUNT(*)),' ','0'),9) AS VARCHAR)+SPACE(740),CHAR(10),''),CHAR(13),'')

预期的结果是文件不包含导出文档的包含十六进制视图中显示的0D和0A字节字符。

EN

回答 3

Stack Overflow用户

发布于 2019-06-07 06:47:15

当您选择“另存结果为”并选择文本文件时,结果是一个制表符分隔的文本文件。每个字段用制表符分隔,每个记录由CR/LF终止。没有办法通过更改查询来改变这一点。

生成的文本文件如下:

该文件以字节顺序标记EF BB BF开头,表示它是UTF-8格式。78、79和7A是“x”、“y”和“z”。它们由制表符(09)分隔,记录以CR/LF (OD/OA)终止。然后对第二个记录执行相同的操作,也由CR/LF终止。

另一方面,您可以选择Copy,运行NotePad,然后粘贴文本。您将在记录之间获得CR/LFs,但在结束时没有。

票数 0
EN

Stack Overflow用户

发布于 2019-06-07 07:01:17

在创建文本文件时,我不能从您所说的(以及下面的评论)看出问题是在SQL级别还是在SQL级别之外。无论哪种方式,您都可以使用NGrams8K来解决这个问题(该链接还包含一个VARCHAR(MAX)版本,它比8K版本慢,但仍然非常快。)

我经常自动化手动更新构建脚本的过程,通过OPENROWSET (或其他)导入它们,修改文本,然后将结果写入新文件以替换旧文件(使用BCP)。下面是一些代码,可以帮助您理解如何使用NGrams函数来解决此问题。

分析:

代码语言:javascript
运行
复制
DECLARE @someString VARCHAR(8000) =
'blah blah blah.... ;
blah blah     .... ;
blah blah blah.... ;
 ...;';

SELECT
  ng.position,
  ng.token,
  charValue   = ASCII(ng.Token),
  binaryValue = CAST(ng.token AS VARBINARY(2))
FROM samd.NGrams8K(@someString,1) AS ng;

返回(为简洁起见进行了删节):

代码语言:javascript
运行
复制
position             token     charValue   binaryValue
-------------------- --------- ----------- -----------
1                    b         98          0x62
2                    l         108         0x6C
3                    a         97          0x61
4                    h         104         0x68
5                              32          0x20
6                    b         98          0x62
...
...
68                   .         46          0x2E
69                   .         46          0x2E
70                   .         46          0x2E
71                             32          0x20
72                   ;         59          0x3B
73                             13          0x0D
74                             10          0x0A
75                             32          0x20
76                             32          0x20
....

注意到第73和74行了吗?这是您想要删除的两个字符: CHAR(13) & CHAR(10) AKA 0D和0A。你想去掉那些。

使用NGrams或NGrams8k,您可以通过定位最后一个字符(13)来获得最后一个LF+CR的位置。

代码语言:javascript
运行
复制
DECLARE @someString VARCHAR(8000) =
'blah blah blah.... ;
blah blah     .... ;
blah blah blah.... ;
 ...;';

SELECT MAX(ng.position)
FROM   samd.NGrams8K(@someString,1) AS ng
WHERE  ASCII(ng.Token) = 13;

返回: 73

注意,我使用了一个变量(@someString)进行演示,如果GUI要添加最终的LF/CR,那么您必须导入该文件并将内容分配给一个变量。

代码语言:javascript
运行
复制
DECLARE @someString VARCHAR(8000) =
'blah blah blah.... ;
blah blah     .... ;
blah blah blah.... ;
 ...;';

-- Use STUFF to remove the last CHAR(13)+CHAR(10)
DECLARE @newString VARCHAR(8000) = 
STUFF(
  @someString,
  (
    SELECT MAX(ng.position)
    FROM   samd.Ngrams8K(@someString,1) AS ng
    WHERE  ASCII(ng.Token) = 13
  ),2,'');

此代码^删除最后的LF/CR。

更新:

我刚刚看到了david的响应;如果是这样的话,您可以使用我的解决方案来拉入文件,更改内容并编写一个新文件。下面是我如何做到这一点的一个例子(不是完美的,但它是有效的)。

代码语言:javascript
运行
复制
CREATE PROC dbo.FileTransform_clean
  @sourceFile NVARCHAR(500),
  @destFile   NVARCHAR(500),
  @badText    NVARCHAR(1000),
  @cleanup    BIT = 1
AS
BEGIN
  -- 0. Prep
  BEGIN
    SET NOCOUNT ON;
    SET @sourceFile = TRIM(@sourceFile);

    DECLARE @pos  SMALLINT       = CHARINDEX('\',REVERSE(@sourceFile));
    DECLARE @path NVARCHAR(4000) = SUBSTRING(@sourceFile,1,LEN(@sourceFile)-@pos),
            @file NVARCHAR(4000) = SUBSTRING(@sourceFile,LEN(@sourceFile)-@pos+2,4000);
    DECLARE @t TABLE (subdirectory NVARCHAR(4000), depth TINYINT, [file] BIT);

    INSERT @t(subdirectory, depth, [file])
      EXEC [master].dbo.xp_DirTree @path,1,1;

    IF NOT EXISTS (SELECT 1 FROM @t AS t WHERE t.subdirectory = @file)
    BEGIN
      DECLARE @error VARCHAR(100) = 
        'The source file, '+ISNULL(@sourceFile,'NULL')+' was not found.';
      PRINT @error;
      GOTO error
    END

    IF OBJECT_ID('tempdb..##import','U') IS NOT NULL DROP TABLE ##import;
    CREATE TABLE ##import(Document VARCHAR(MAX));
  END

  -- 1. File Import
  BEGIN
    PRINT 'Performing file import...';

    DECLARE @SQL NVARCHAR(4000) = 'INSERT INTO ##import(Document)
    SELECT * FROM OPENROWSET (BULK N'''+@sourceFile+''', SINGLE_BLOB) AS Document;';

    EXEC (@SQL);
  END

  -- 2. Transformation
  BEGIN
    PRINT 'Performing file transform...';

    DECLARE @query NVARCHAR(4000) = 
      N'SELECT STRING_AGG(s.item,CHAR(10)) WITHIN GROUP (ORDER BY s.ItemNumber)
        FROM   SQLToolbox_Misc.samd.delimitedSplitAB((SELECT i.Document FROM ##import AS i),CHAR(10)) AS s
        WHERE NOT EXISTS (SELECT 1 FROM STRING_SPLIT('''+@badText+''','','') AS ss 
                  WHERE CHARINDEX(ss.[value],s.item)>0);'

    SET @SQL = 'bcp '+'"'+@query+'" '+'queryout "'+@destFile+'" -c -T -S '+@@SERVERNAME;
    SET @SQL = REPLACE(@sql,CHAR(13)+CHAR(10),'');

    DECLARE @SQLText VARCHAR(8000) = '  Executing:'+CHAR(10)+'  '+@SQL;
    PRINT @SQLText;

    EXEC [master]..xp_cmdshell @SQL;
    IF @cleanup = 1 DROP TABLE ##import;
  END

  error:
END

这段代码做了一些完全不同的事情,但你可以注意到我是如何做的: 1.使用OPENROWSET 2.对文件内容做一些操作(在我的代码中,我删除了@badText 3.使用BCP编写一个新文件

希望这能有所帮助。

票数 0
EN

Stack Overflow用户

发布于 2019-06-07 22:42:53

可能有更好的自动化方法,但要回答所提出的问题,您可以取消选中Op中的"Retain /LF on copy or save“复选框

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56480848

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档