【问题标题】:SQL function parsing out text from a columnSQL 函数从列中解析出文本
【发布时间】:2018-05-09 20:19:24
【问题描述】:

我有一个表格,上面有一些我想解析出来的文本,我非常接近解决方案,但它并不完全存在。我有一个名为 indicatornumerator 的列,我想解析出类似于下面的内容,即我想将方括号之间的每个值都放到一个新行上。正如您从下面的输出中看到的那样,我在减号之后得到了第一个值的重复。这不会发生在那些没有减号的人身上。

我的功能如下:

alter function fn_breakdown (@string varchar(max))
returns @breakdown table
(
    originalstr varchar(max),
    breakdownstr varchar(max)
)
as
begin
    while charindex('r',@string,1) >0
    begin
        insert into @breakdown
        select @string,
        SUBSTRING(@string,CHARINDEX('r',@string,1),CHARINDEX(']',@string,1)-CHARINDEX('r',@string,1))
        set @string = right(@string,len(@string)-CHARINDEX(')',@string,1))
    end
    return
end

我想做的第二件事是将减号之后的那些作为负值返回,而不是例如。 -R101 而不是 R101,因为我需要稍后减去这些值。

非常感谢任何帮助

下面应该创建一个临时表,并将显示我得到的输出。您会看到其中一行重复。我希望在指标分子列中以“R”开头的每个值都有一行

创建表 #temped2 ( 指标分子 varchar(max) )

插入#temped2 选择'(SUM([R4]) + SUM([R1010])) - (SUM([R1035]) + SUM([R1034]))'

从 #temped2 中选择 * 交叉应用 fn_breakdown(indicatornumerator)

【问题讨论】:

  • 请举例说明预期的输出。
  • 请指定您的关系型数据库
  • 示例输出在屏幕截图中。左边是原始字符串,右边是所需的输出。我希望将原始字符串解析为单独的行,但正如您在屏幕截图中看到的那样,有些是重复的。我也在使用 SQL Server 2017
  • 不要发布截图。发布 DML。
  • 对于您的第一个问题,请尝试将 SET 中的 ')' 替换为 ']'。对于第二个问题,您可能想要搜索算术表达式的解析并从中获取原子。因为这实际上就是您在这里尝试做的事情。但请注意,您的括号是不平衡的。我认为IndicatorNumerator的开头缺少一个'('。

标签: sql sql-server function tsql


【解决方案1】:

下载一份ngrams8k,然后:

-- sample data
DECLARE @yourtable TABLE (IndicatorNumerator varchar(1000));
INSERT @yourtable
SELECT 'SUM([R4]) + SUM([R1010]) - SUM([R50]) + SUM([R200])' UNION ALL
SELECT 'SUM([R554]) + SUM([R210]) - SUM([R500]) + SUM([R999])';

-- Solution
SELECT 
  t.IndicatorNumerator,
  breakdownstr = substring(t.IndicatorNumerator, ng.position+1, n.d-ng.position-1)
FROM @yourtable t
CROSS APPLY dbo.ngrams8k(t.IndicatorNumerator, 2) ng
CROSS APPLY (VALUES (charindex(']',t.IndicatorNumerator, ng.position+1))) n(d)
WHERE ng.token = '[R';

返回:

IndicatorNumerator                                       breakdownstr
-------------------------------------------------------- --------------
SUM([R4]) + SUM([R1010]) - SUM([R50]) + SUM([R200])      R4
SUM([R4]) + SUM([R1010]) - SUM([R50]) + SUM([R200])      R1010
SUM([R4]) + SUM([R1010]) - SUM([R50]) + SUM([R200])      R50
SUM([R4]) + SUM([R1010]) - SUM([R50]) + SUM([R200])      R200
SUM([R554]) + SUM([R210]) - SUM([R500]) + SUM([R999])    R554
SUM([R554]) + SUM([R210]) - SUM([R500]) + SUM([R999])    R210
SUM([R554]) + SUM([R210]) - SUM([R500]) + SUM([R999])    R500
SUM([R554]) + SUM([R210]) - SUM([R500]) + SUM([R999])    R999

【讨论】:

    【解决方案2】:

    如果您使用的是 SQL Server 2016 和 avove,请尝试此代码

    ;WITH cte_date
        AS
        (
            SELECT indicatornumerator, REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(indicatornumerator,'(',''),')',''),'[',''),']',''),'SUM',''),'- ','-') ParsedData 
            FROM #temped2
        )
    SELECT *
    FROM cte_date
    CROSS APPLY STRING_SPLIT(ParsedData, ' ')
    WHERE [VALUE] != '+';
    

    以下脚本将在 sql server 2016 之前运行

    CREATE FUNCTION [dbo].[StrParse]
                   (@delimiter CHAR(1),  
                    @csv       NTEXT)  
    RETURNS @tbl TABLE(Keys  NVARCHAR(255))  
    AS  
    
      BEGIN  
        DECLARE  @len INT  
        SET @len = Datalength(@csv)  
        IF NOT @len > 0  
          RETURN  
    
        DECLARE  @l INT  
        DECLARE  @m INT  
    
        SET @l = 0  
        SET @m = 0  
    
        DECLARE  @s VARCHAR(255)  
        DECLARE  @slen INT  
    
        WHILE @l <= @len  
          BEGIN  
    
            SET @l = @m + 1--current position  
            SET @m = Charindex(@delimiter,Substring(@csv,@l + 1,255)) 
    
            IF @m <> 0  
              SET @m = @m + @l  
            --insert @tbl(keys) values(@m)  
            SELECT @slen = CASE   
                             WHEN @m = 0 THEN 255 
                             ELSE @m - @l  
                           END  
    
            IF @slen > 0  
              BEGIN  
                SET @s = Substring(@csv,@l,@slen)  
                INSERT INTO @tbl  
                           (Keys)  
                SELECT @s  
              END  
    
            SELECT @l = CASE   
                          WHEN @m = 0 THEN @len + 1  
                          ELSE @m + 1  
                        END 
          END  
    
        RETURN  
      END
    
    GO
    
    ;WITH cte_date
        AS
        (
            SELECT indicatornumerator, REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(indicatornumerator,'(',''),')',''),'[',''),']',''),'SUM',''),'- ','-'),'+ ','') ParsedData 
            FROM #temped2
        )
    SELECT *
    FROM cte_date
    CROSS APPLY dbo.StrParse(' ', ParsedData)
    go
    

    【讨论】:

    • 这只有在 OP 使用 SQL 2016+ 时才有效。 (对于 OP 来说,包括他们在发布时使用的 SQL 版本是一个很好的论据)
    猜你喜欢
    • 2014-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多