如何将一列拆分为多列

Posted

技术标签:

【中文标题】如何将一列拆分为多列【英文标题】: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') 在提出问题时,您需要提供一个可重现的最小示例。请参考以下链接:***.com/help/minimal-reproducible-example 请提供以下内容: (1) DDL 和样本数据填充,即 CREATE table(s) 加上 INSERT T-SQL 语句。 (2) 你需要做什么,即逻辑和你的代码尝试在 T-SQL 中实现它。 (3) 期望的输出,基于上面#1 中的样本数据。 (4) 你的 SQL Server 版本 (SELECT @@version;) 【参考方案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     |
+----+------+--------------+-----------+

【讨论】:

以上是关于如何将一列拆分为多列的主要内容,如果未能解决你的问题,请参考以下文章

将一列拆分为多列,计数频率:“int”对象不可迭代

如何将oracle 中一条数据拆分成多条

使用 SSIS OR T-SQL 将一列带引号和不带引号的逗号分隔值拆分为多列

excel 里如何把一列单元格拆分成两列

SQL Server将一列拆分成多列

如何在标准sql-大查询中将一列拆分为多列