【问题标题】:How to parse a string and create several columns from it?如何解析字符串并从中创建几列?
【发布时间】:2011-08-15 07:57:57
【问题描述】:

我有一个包含名称值对的varchar(max) 字段,在每一行中我都有名称下划线值。

我需要对其进行查询,以便它在两列中返回名称、值对(因此通过解析文本、删除下划线和“新行”字符。

所以从这里

select NameValue from Table

我在哪里得到这个文本:

Name1_Value1
Name2_Value2
Name3_Value3

我想要这个输出

Names  Values
=====  ======
Name1  Value1
Name2  Value2
Name3  Value3

【问题讨论】:

  • 我关闭了这个问题,因为我问了一个更接近我真正问题的新问题:stackoverflow.com/questions/5830065/…
  • 无需关闭。您可以编辑您的问题
  • 是的,你是对的,我真的很着急!
  • 正确的做法是进行适当的设计,这样您在一个字段中就不会拥有多个信息。您应该将其存储为两个字段,这样您就不必在每次想要查看数据时都编写讨厌的代码来正确查看数据。每当您有一段数据必须运行函数才能正确查看时,您需要考虑重构设计。数据库设计最基本的规则之一是每个字段包含一个且唯一的信息。每次选择数据时最好在插入数据时解析一次。

标签: sql-server sql-server-2008 text-parsing


【解决方案1】:
SELECT substring(NameValue, 1, charindex('_', NameValue)-1) AS Names, 
  substring(NameValue, charindex('_', NameValue)+1, LEN(NameValue)) AS Values
FROM Table

编辑: 像这样放置在函数或存储过程中并与临时表相结合的东西应该适用于多行,具体取决于行分隔符,您还应该在开始之前删除 CHAR(13)

DECLARE @helper varchar(512)
DECLARE @current varchar(512)
SET @helper = NAMEVALUE
WHILE CHARINDEX(CHAR(10), @helper) > 0 BEGIN
    SET @current = SUBSTRING(@helper, 1, CHARINDEX(CHAR(10), NAMEVALUE)-1)
    SELECT SUBSTRING(@current, 1, CHARINDEX('_', @current)-1) AS Names, 
      SUBSTRING(@current, CHARINDEX('_', @current)+1, LEN(@current)) AS Names
    SET @helper = SUBSTRING(@helper, CHARINDEX(CHAR(10), @helper)+1, LEN(@helper))
END
SELECT SUBSTRING(@helper, 1, CHARINDEX('_', @helper)-1) AS Names, 
  SUBSTRING(@helper, CHARINDEX('_', @helper)+1, LEN(@helper)) AS Names

【讨论】:

  • 所以你的数据库设计很糟糕?如果您有不止一行,则必须在函数或存储过程中执行此操作。查看我的编辑。
  • 不,我需要做的是一种临时工作,用于模拟我没有的新领域,当然我一有时间就会删除它。
【解决方案2】:
 DECLARE @TExt NVARCHAR(MAX)= '***[ddd]***
    dfdf
    fdfdfdfdfdf
    ***[fff]***
    4545445
    45454
    ***[ahaASSDAD]***

    DFDFDF
    ***[SOME   TEXT]***
    '

    DECLARE @Delimiter VARCHAR(1000)= CHAR(13) + CHAR(10) ;
    WITH    numbers
              AS ( SELECT   ROW_NUMBER() OVER ( ORDER BY o.object_id, o2.object_id ) Number
                   FROM     sys.objects o
                            CROSS JOIN sys.objects o2
                 ),
            c AS ( SELECT   Number CHARBegin ,
                            ROW_NUMBER() OVER ( ORDER BY number ) RN
                   FROM     numbers
                   WHERE    SUBSTRING(@text, Number, LEN(@Delimiter)) = @Delimiter
                 ),
            res
              AS ( SELECT   CHARBegin ,
                            CAST(LEFT(@text, charbegin) AS NVARCHAR(MAX)) Res ,
                            RN
                   FROM     c
                   WHERE    rn = 1
                   UNION ALL
                   SELECT   c.CHARBegin ,
                            CAST(SUBSTRING(@text, res.CHARBegin,
                                           c.CHARBegin - res.CHARBegin) AS NVARCHAR(MAX)) ,
                            c.RN
                   FROM     c
                            JOIN res ON c.RN = res.RN + 1
                 )
        SELECT  *
        FROM    res

【讨论】:

    【解决方案3】:

    他是你可以借鉴的例子:

    -- Creating table:
    create table demo (dID int, dRec varchar(100));
    
    -- Inserting records:
    insert into demo (dID, dRec) values (1, 'BCQP1 Sam');
    insert into demo (dID, dRec) values (2, 'BCQP2 LD');
    
    -- Selecting fields to retrive records:
    select * from demo;
    

    然后我想在一行中显示两行组合并仅显示左侧的值,删除右侧的名称直到空格字符。

        /*
        The STUFF() function puts a string in another string, from an initial position.  
        The LEFT() function returns the left part of a character string with the specified number of characters. 
        The CHARINDEX() string function returns the starting position of the specified expression in a character string. 
    */
    SELECT 
     DISTINCT
       STUFF((SELECT ' ' + LEFT(dt1.dRec, charindex(' ', dt1.dRec) - 1) 
              FROM demo dt1
              ORDER BY dRec
              FOR XML PATH('')), 1, 1, '') [Convined values]
    FROM demo dt2
    --
    GROUP BY dt2.dID, dt2.dRec
    ORDER BY 1
    

    正如您在此处看到的,当您运行该函数时,输出将是:

    BCQP1 BCQP2
    

    在脚本的顶部,我解释了每个函数的用途(STUFF()、LEFT()、CHARINDEX() 函数)我还使用了 DISTINCT 来消除重复值。

    注意:dt 代表“demo table”,我使用同一张表并使用了两个别名 dt1 和 dt2,dRec 代表“demo Record”

    如果你想了解更多关于 STUFF() 函数的信息,这里有一个链接:

    https://www.mssqltips.com/sqlservertip/2914/rolling-up-multiple-rows-into-a-single-row-and-column-for-sql-server-data/

    【讨论】:

      【解决方案4】:

      对于 CTE,如果超过 100 个项目,您将遇到递归问题

      Msg 530, Level 16, State 1, Line 20 语句终止。这 在语句完成之前,最大递归 100 已用完。

      DECLARE @TExt NVARCHAR(MAX)
      SET @TExt = '100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203'
      
      
      DECLARE @Delimiter VARCHAR(1000)= ',';
      WITH    numbers
                AS ( SELECT   ROW_NUMBER() OVER ( ORDER BY o.object_id, o2.object_id ) Number
                     FROM     sys.objects o
                              CROSS JOIN sys.objects o2
                   ),
              c AS ( SELECT   Number CHARBegin ,
                              ROW_NUMBER() OVER ( ORDER BY number ) RN
                     FROM     numbers
                     WHERE    SUBSTRING(@text, Number, LEN(@Delimiter)) = @Delimiter
                   ),
              res
                AS ( SELECT   CHARBegin ,
                              CAST(LEFT(@text, charbegin) AS NVARCHAR(MAX)) Res ,
                              RN
                     FROM     c
                     WHERE    rn = 1
                     UNION ALL
                     SELECT   c.CHARBegin ,
                              CAST(SUBSTRING(@text, res.CHARBegin,
                                             c.CHARBegin - res.CHARBegin) AS NVARCHAR(MAX)) ,
                              c.RN
                     FROM     c
                              JOIN res ON c.RN = res.RN + 1
                   )
          SELECT  *
          FROM    res
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多