如何将单独列中冒号前后的单词拆分为sql中的行
Posted
技术标签:
【中文标题】如何将单独列中冒号前后的单词拆分为sql中的行【英文标题】:how to split words before and after colon in separate columns to rows in sql 【发布时间】:2019-05-30 15:39:12 【问题描述】:我在表中有一个列 [LongText],它的行值是所有属性及其值的合并。下面是示例。 我们可以将单词前后的冒号分成两列,如预期结果所示?在 sql 2014 中需要它
Longtext
TYPE: SOLID WEDGE 1,SOLID WEDGE 2, VALVE SIZE: 1 IN, PRESSURE RATING: 800 LB, CONNECTION TYPE: SOCKET WELD, BONNET STYLE: BOLTED
预期输出为 2 列属性和值:
Attribute | Value
----------------------------------------------
TYPE | SOLID WEDGE 1,SOLID WEDGE 2
VALVE SIZE | 1 IN
PRESSURE RATING | 800 LB
CONNECTION TYPE | SOCKET WELD
BONNET STYLE | BOLTED
【问题讨论】:
处理这个问题的一个好方法是通过正则表达式。不幸的是,SQL Server 对正则表达式的支持很弱,所以它不是进行这种清理的最佳场所。在将数据导入 SQL Server 之前,您是否有机会使用其他工具清理数据? 你好,蒂姆,你能举一些正则表达式的例子吗 如果这是一次性数据加载,您可以编写一个while
循环,从字符串中删除第一个键/值对,将它们写入新表并继续直到字符串空的。或者,使用其他一些具有丰富正则表达式功能的编程语言来完成这项工作。 (如果这不是一次性数据加载,我不建议使用循环)
STRING_SPLIT() 可能有用.. (docs.microsoft.com/en-us/sql/t-sql/functions/…)
@Sai 你在回答部分检查了我的代码吗?
【参考方案1】:
看看这是否有帮助。另外,如果您希望我解释代码,请告诉我。
IF EXISTS(SELECT 1 FROM SYS.OBJECTS WHERE NAME = 'fn_GetAttributeAndValueFromLongText' AND TYPE = 'TF')
BEGIN
DROP FUNCTION dbo.fn_GetAttributeAndValueFromLongText
END
GO
CREATE FUNCTION dbo.fn_GetAttributeAndValueFromLongText ( @String_LongText VARCHAR(MAX) )
RETURNS @TBL_Attribute_Value TABLE
(
Attribute VARCHAR(MAX)
, Value VARCHAR(MAX)
)
AS
BEGIN
DECLARE @ATTR_VALUE_DELIMITER AS VARCHAR(MAX) = ':'
WHILE (RTRIM(LTRIM(LEN(@String_LongText))) != 0)
BEGIN
DECLARE @String_ATTR VARCHAR(MAX)='', @String_VALUE VARCHAR(MAX)= ''
SELECT @String_LongText = RTRIM(LTRIM(@String_LongText))
SELECT @String_ATTR = SUBSTRING(@String_LongText, 1,CHARINDEX(':',@String_LongText)-1)
SELECT @String_LongText = RIGHT(@String_LongText, LEN(@String_LongText)-(LEN(@String_ATTR)+1))
IF @String_LongText LIKE '%'+@ATTR_VALUE_DELIMITER+'%'
BEGIN
SELECT @String_VALUE = LEFT(SUBSTRING(@String_LongText, 1, CHARINDEX(':', @String_LongText)-1), LEN(SUBSTRING(@String_LongText, 1, CHARINDEX(':', @String_LongText)-1)) - CHARINDEX(',', REVERSE(SUBSTRING(@String_LongText, 1, CHARINDEX(':', @String_LongText)-1))))
SELECT @String_LongText = RIGHT(@String_LongText, LEN(@String_LongText)-(LEN(@String_VALUE)+1))
END
ELSE
BEGIN
SELECT @String_VALUE = @String_LongText
SELECT @String_LongText = REPLACE(@String_LongText, @String_VALUE, '')
END
INSERT INTO @TBL_Attribute_Value ([Attribute], [Value])
VALUES(RTRIM(LTRIM(@String_ATTR)), RTRIM(LTRIM(@String_VALUE)))
END
RETURN
END
GO
SELECT * FROM dbo.fn_GetAttributeAndValueFromLongText('TYPE: SOLID WEDGE 1,SOLID WEDGE 2, VALVE SIZE: 1 IN, PRESSURE RATING: 800 LB, CONNECTION TYPE: SOCKET WELD, BONNET STYLE: BOLTED')
【讨论】:
【参考方案2】:开始使用 STRING_SPLIT(),类似于:
DECLARE @string varchar(max) = 'TYPE: SOLID WEDGE 1,SOLID WEDGE 2, VALVE SIZE: 1 IN, PRESSURE RATING: 800 LB .....';
DECLARE @output varchar(max) = '';
DECLARE @v varchar(max) = (SELECT TOP(1) value from string_split(@string,' '));
WHILE @v <> ''
BEGIN
select @v;
SET @string = (SELECT ltrim(substring(@string,LEN(@v)+1,1024)));
select @string;
SET @v = (SELECT TOP(1) value from string_split(@string,' '));
END
给出:
正如@Tim 所说,不能保证上述方法的顺序是正确的。
所以,第二次尝试?:
DECLARE @string varchar(max) = 'TYPE: SOLID WEDGE 1,SOLID WEDGE 2, VALVE SIZE: 1 IN, PRESSURE RATING: 800 LB, CONNECTION TYPE: SOCKET WELD, BONNET STYLE: BOLTED';
SELECT * FROM string_split(REPLACE(@string,' ','#'),'#');
这希望(='does-not-check')原始字符串中没有“#”字符。
【讨论】:
这个答案可能无法正常工作,因为STRING_SPLIT
不保证会保持单词的顺序。以上是关于如何将单独列中冒号前后的单词拆分为sql中的行的主要内容,如果未能解决你的问题,请参考以下文章
如何将存储在列中的 JSON 数组中的每个元素的行拆分为一行?
如何在 BigQuery SQL 中将字符串列拆分为多行单个单词和单词对?