【问题标题】:Performing operations in text file using T-SQL使用 T-SQL 在文本文件中执行操作
【发布时间】:2024-04-19 17:00:02
【问题描述】:

我有一个文本文件,需要在其中执行操作,比如文件有标题,如果有标题,那么它传递给下一个,如果没有,那么操作应该停止。 第二步找到有正确的分隔符,即管道如果文件有正确的分隔符,那么它应该通过并移动下一步,否则失败。 如果上述所有步骤都成功,那么它应该被导出到主表。

文件结构为:

A|B|C|D|E - column
00|1|1|1|1- data
.

。 以此类推。

create table #testdata (
textvalue varchar(max)
)


bulk insert #testdata
from 'D:\test.txt'
--with 
--(
--FIELDTERMINATOR = '|'
--)

select  *,rowid = row_number() over(order by textvalue desc) 
into    #test1
from    #testdata


--if exists (select 1 from #test1 where #test1.textvalue = @header and #test1.rowid = 1)
--begin
goto nextstep
--end
else
goto exitprocedure

输出应该是这样的:-

select FileType = 'Test',
       ReviewType = 'Correct delimiter is expected',
       PassFail = 'Success or Fail'

基于上述验证,无论哪个失败,它都应显示上述三个字段的输出。

由于这需要在 T-SQL 中执行。

【问题讨论】:

  • SO 是关于帮助您构建解决方案,而不是为您完成所有工作。当您遇到困难时,请尝试并发布一个具体问题。
  • 你需要edit那个细节问题。
  • SO 不是免费的编码服务网站!!!您应该尝试解决您的问题。如果它不起作用,我们会尽力提供帮助。
  • 另外,阅读本文以了解如何提问。 *.com/help/how-to-ask
  • 我不同意 SSIS 是为此而构建的。如果文件没有固定的格式或者它很脏,你必须求助于 C# 脚本等。SSIS 不能很好地处理不一致的输入数据格式。

标签: sql-server file tsql sql-server-2016


【解决方案1】:

正如您已经被告知的那样,T-SQL 不是用于此目的的正确工具...

字符串操作能力相当弱,但您可以尝试以下方法之一:

我开始使用包含您的文本文件内容的变量进行模拟。

DECLARE @YourFile VARCHAR(MAX)=
'A|B|C|D|E
01|1|1|1|1
02|2|2|2|2';

--声明换行符和分隔符的变量

DECLARE @YourLineBreak VARCHAR(2)=CHAR(13)+CHAR(10); --might differ...
DECLARE @YourDelimiter VARCHAR(1)='|';

--此查询会将您的文件转换为 XML

DECLARE @YourInput XML=
CAST(CONCAT('<line><val>'
    ,REPLACE(REPLACE(@YourFile,@YourDelimiter,'</val><val>'),@YourLineBreak,'</val></line><line><val>')
    ,'</val></line>') AS XML);

SELECT @YourInput;

--此查询将返回列名

SELECT A.cols.value('text()[1]','varchar(max)') AS ColumnName
FROM @YourInput.nodes('/line[1]/*') A(cols) ;

--此查询将每个数据行作为单行返回

WITH CountRows(LineIndex) AS(SELECT TOP((SELECT @YourInput.value('count(/line)','int')-1)) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values)
SELECT LineIndex
      ,@YourInput.query('/line[sql:column("LineIndex")+1]') AS LineValues
FROM CountRows;

--在这个查询中我先注入一个数字序列,以后可以在XQuery中使用

WITH InjectSequence(Combined) AS
(
    SELECT (SELECT TOP((SELECT @YourInput.value('count(/line[1]/val)','int'))) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values FOR XML PATH('Nmbr'),TYPE)
          ,@YourInput
    FOR XML PATH(''),TYPE
)
SELECT Combined.query
('
    let $cols := /line[1]/val
    for $ln in /line[position()>1]
    return
    <line>
    {
        for $nr in /Nmbr/text() 
        let $n := xs:int($nr)
        return
        <val name="{$cols[$n]}" value="{$ln/val[$n]}" />
    }
    </line>
')
FROM InjectSequence;

无论您选择哪种方法,如果手动工作,您将不得不做很多事情。

最终查询必须是动态创建的,或者您可以保留在通用容器中,例如 XML 或 JSON。

SQL-Server 2016 有 JSON

对于 v2016+,您也可以尝试 JSON 路由:

SELECT B.*
FROM OPENJSON(CONCAT('[',STUFF(CONCAT(',[["',REPLACE(REPLACE(@YourFile,@YourDelimiter,'","'),@YourLineBreak,'"],["'),'"]]'),1,1,''),']')) A
CROSS APPLY OPENJSON(A.[value])
WITH(col1 VARCHAR(MAX) '$[0]'
    ,col2 VARCHAR(MAX) '$[1]'
    ,col3 VARCHAR(MAX) '$[2]'
    ,col4 VARCHAR(MAX) '$[3]'
    ,col5 VARCHAR(MAX) '$[4]') B --add as many as you need

祝你好运!

【讨论】:

    最近更新 更多