如何将一列拆分为多列
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
我使用了patindex
和charindex
,但结果不正确。
请帮我处理 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】:这是一个通用的解决方案。它将处理任何令牌之间的未知数量的空格。
col1 和 col2 列检索很简单,但 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 |
+----+------+--------------+-----------+
【讨论】:
以上是关于如何将一列拆分为多列的主要内容,如果未能解决你的问题,请参考以下文章