【问题标题】:How to split one column into multiple columns如何将一列拆分为多列
【发布时间】:2021-03-02 22:14:59
【问题描述】:

我有一个 SQL 表:

column1
--------
05 MODE-PARTNER      MIC Z(7)9
08 MODE-FLERS01      MIC X

输出:

column1    column2        column3
----------------------------------
05         MODE-PARTNER   MIC Z(7)9
08         MODE-FLERS01   MIC X

我使用了patindexcharindex,但结果不正确。 请帮我处理 SQL 查询。

我的查询:

select
    column4
    , LEFT(column4, PATINDEX('%[0-9][^0-9]%', column4 )) AS column1 
    , LTRIM(RIGHT(column4, LEN(column4) - PATINDEX('%[0-9][^0-9]%', column4 ))) As column2
    , CASE WHEN CHARINDEX('PIC',column4)>0 THEN ltrim(SUBSTRING(column4,1,CHARINDEX('PIC',column4)-1)) ELSE column4 END column2_new
    , CASE WHEN CHARINDEX('PIC',column4)>0 THEN ltrim(SUBSTRING(column4,CHARINDEX('PIC',column4)-0,len(column4))) ELSE NULL END AS column3
from table1
where column4 IN ('05 MODE-PARTNER MIC Z(7)9','08 MODE-FLERS01 MIC X') 

【问题讨论】:

  • 选择 column4 ,LEFT(column4, PATINDEX('%[0-9][^0-9]%', column4 )) AS column1 ,LTRIM(RIGHT(column4, LEN(column4) - PATINDEX('%[0-9][^0-9]%', column4 ))) As column2,CASE WHEN CHARINDEX('PIC',column4)>0 THEN ltrim(SUBSTRING(column4,1,CHARINDEX('PIC ',column4)-1)) ELSE column4 END column2_new,CASE WHEN CHARINDEX('PIC',column4)>0 THEN ltrim(SUBSTRING(column4,CHARINDEX('PIC',column4)-0,len(column4))) ELSE NULL END AS column3 from table1 where column4 IN ('05 MODE-PARTNER MIC Z(7)9','08 MODE-FLERS01 MIC X')
  • 在提出问题时,您需要提供一个可重现的最小示例。请参考以下链接:stackoverflow.com/help/minimal-reproducible-example 请提供以下内容: (1) DDL 和样本数据填充,即 CREATE table(s) 加上 INSERT T-SQL 语句。 (2) 你需要做什么,即逻辑和你的代码尝试在 T-SQL 中实现它。 (3) 期望的输出,基于上面#1 中的样本数据。 (4) 你的 SQL Server 版本 (SELECT @@version;)

标签: sql sql-server tsql


【解决方案1】:

ParseName() 是一个选项,前提是您的模式是一致的

示例

Declare @YourTable Table ([column1] varchar(50))
Insert Into @YourTable Values 
 ('05 MODE-PARTNER MIC Z(7)9')
,('08 MODE-FLERS01 MIC X')


Select column1 = parsename(S,4)
      ,column2 = parsename(S,3)
      ,column3 = concat(parsename(S,2),' ',parsename(S,1))
 from @YourTable
 Cross Apply ( values ( replace(column1,' ','.') ))B(S)

退货

column1 column2         column3
05      MODE-PARTNER    MIC Z(7)9
08      MODE-FLERS01    MIC X

【讨论】:

  • 聪明!我喜欢它。
  • @DaleK 感谢您的笑容。我们只能希望实际数据是真实的
  • 是的,它不能很好地处理 OP 所显示的多个空格。
  • @John 不,当我在整个表上应用查询时,结果集出错并显示为 NULL
  • @RakeshMishra 我怀疑超过 4 个空格。 ParseName() 最多只能消耗 4 个项目
【解决方案2】:

假设提供的示例是指示性的,只需在空格处查找并拆分即可。

select
  -- Split out the first section
  substring(x.col1,1,FirstSpace-1) Column1
  -- Split out the second section
  , substring(SecondString, 1, SecondSpace-1) Column2
  -- Split out the third section
  , ltrim(substring(SecondString,SecondSpace,len(SecondString))) Column3
from (values ('05 MODE-PARTNER      MIC Z(7)9'), ('08 MODE-FLERS01      MIC X')) x (col1)
-- Find the first space
cross apply (values (charindex(' ', x.col1))) a (FirstSpace)
-- Remove the first section + spaces
cross apply (values (ltrim(substring(x.col1,FirstSpace+1,len(x.col1))))) b (SecondString)
-- Find the second space
cross apply (values (charindex(' ', SecondString))) z (SecondSpace)

【讨论】:

    【解决方案3】:

    这适用于给出的示例:

    declare
        @t table (Fld varchar (1000))
    
    insert into @t
    values
    ('05 MODE-PARTNER      MIC Z(7)9'),
    ('08 MODE-FLERS01      MIC X')
    
    select LEFT(Fld, charindex(' ', Fld) - 1) column1
        , trim(SUBSTRING(Fld, charindex(' ', Fld)+1, len(Fld) - CHARINDEX(' ', reverse(Fld)) - charindex(' ', Fld)-3)) column2
        , REVERSE(LEFT(reverse(Fld), charindex(' ', reverse(Fld)) +3)) column3
    from @t 
    

    输出:

    column1 column2 column3
    05  MODE-PARTNER    MIC Z(7)9
    08  MODE-FLERS01    MIC X
    

    【讨论】:

    • @Dale 感谢 Dale,但表格列包含其他字母数字文本,并且当我尝试在整个表格上运行时出现错误:“传递给 LEFT 或 SUBSTRING 函数的长度参数无效。”
    • @RakeshMishra 那么您需要确保您的问题包含/解释所有可能性,即包含您要解决的确切问题的minimal reproducible example。并且根据您的实际情况调整其中一种解决方案应该不会太难。
    【解决方案4】:

    这是一个通用的解决方案。它将处理任何令牌之间的未知数量的空格。

    col1col2 列检索很简单,但 col3 检索更有趣。

    SQL

    -- DDL and sample data population, start
    DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, column1 VARCHAR(MAX));
    INSERT INTO @tbl VALUES 
    ('05 MODE-PARTNER     MIC Z(7)9'),
    ('08   MODE-FLERS01   MIC X');
    -- DDL and sample data population, end
    
    DECLARE @separator CHAR(1) = SPACE(1);
    
    WITH rs AS
    (
        SELECT * 
        , TRY_CAST('<root><r><![CDATA[' + 
                REPLACE(column1 COLLATE Czech_BIN2, @separator, ']]></r><r><![CDATA[') + ']]></r></root>' AS XML)
           .query('<root>{for $x in /root/r[text()] return $x}</root>') AS xmldata
        FROM @tbl
    )
    SELECT ID
        , c.value('(r[1]/text())[1]', 'VARCHAR(30)') AS col1
        , c.value('(r[2]/text())[1]', 'VARCHAR(30)') AS col2
        , c.query('data(r[position() gt 2])').value('. cast as xs:token?', 'VARCHAR(MAX)') AS col3
    FROM rs 
        CROSS APPLY xmldata.nodes('/root') AS t(c);
    

    输出

    +----+------+--------------+-----------+
    | ID | col1 |     col2     |   col3    |
    +----+------+--------------+-----------+
    |  1 |   05 | MODE-PARTNER | MIC Z(7)9 |
    |  2 |   08 | MODE-FLERS01 | MIC X     |
    +----+------+--------------+-----------+
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-23
      • 1970-01-01
      • 2014-12-16
      • 2019-05-10
      相关资源
      最近更新 更多