我需要将多值列分成单个值
SOS_ID ALLOCATED_PART_NBR ALLOCATED_SALES_ITM ALLOCATED_QTY
523 500~5008~038~5008 2302~~007~5û005 1~1~~~1~2
注意:如果~
分隔符之间没有值,则应插入空字符串。
我希望输出如下:
SOS_ID ALLOCATED_PART_NBR ALLOCATED_SALES_ITM ALLOCATED_QTY
523 500 2302 1
523 5008 '' 1
523 038 007 ''
523 5008 5û005 ''
523 ''/NULL ''/NULL 1
523 ''/NULL ''/NULL 2
答案 0 :(得分:1)
所以......这是我为你想要的东西而工作的一种方法。首先,您需要一个表值函数,它将字符串拆分为基于分隔符的字段,并将填充返回指定长度的行数:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[SplitString]') AND type IN (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[SplitString]
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[SplitString] (
@delimitedString nvarchar(4000),
@delimiter nvarchar(100),
@padRows int
)
/**************************************************************************
DESCRIPTION:
Accepts a delimited string and splits it at the specified
delimiter points. Returns the individual items as a table data
type with the ElementID field as the array index and the Element
field as the data
PARAMETERS:
@delimitedString - The string to be split
@delimiter - String containing the delimiter where
delimited string should be split
@padRows - Any rows less than this value will be padded
with empty rows (NULL means no padding)
RETURNS:
Table data type containing array of strings that were split with
the delimiters removed from the source string
USAGE:
SELECT ElementID, Element
FROM asi_SplitString('11111,22222,3333', ',', NULL)
ORDER BY ElementID
***************************************************************************/
RETURNS @tblArray TABLE
(
ElementID int IDENTITY(1,1),
Element nvarchar(1000)
)
AS
BEGIN
DECLARE @index int
DECLARE @siStart int
DECLARE @siDelSize int
DECLARE @count int
SET @count = 1;
SET @siDelSize = LEN(@delimiter);
--loop through source string and add elements to destination table array
WHILE LEN(@delimitedString) > 0
BEGIN
SET @index = CHARINDEX(@delimiter, @delimitedString);
IF @index = 0
BEGIN
INSERT INTO @tblArray VALUES (@delimitedString);
BREAK;
END
ELSE
BEGIN
INSERT INTO @tblArray VALUES(SUBSTRING(@delimitedString, 1,@index - 1));
SET @siStart = @index + @siDelSize;
SET @delimitedString = SUBSTRING(@delimitedString, @siStart , LEN(@delimitedString) - @siStart + 1);
END
SET @count += 1;
END
IF (@padRows IS NOT NULL)
WHILE (@count < @padRows)
BEGIN
SET @count += 1;
INSERT INTO @tblArray VALUES ('');
END
RETURN;
END
GO
现在你需要一个带有数据的样本表来测试这个(基于你的问题):
CREATE TABLE TestTable (SOS_ID nvarchar(10),
ALLOCATED_PART_NBR nvarchar(400),
ALLOCATED_SALES_ITM nvarchar(400),
ALLOCATED_QTY nvarchar(400))
INSERT INTO TestTable (SOS_ID, ALLOCATED_PART_NBR, ALLOCATED_SALES_ITM, ALLOCATED_QTY)
VALUES ('523', '500~5008~038~5008', '2302~~007~5û005', '1~1~~~1~2')
现在,一些代码会将上面的数据转换为您想要的结果:
DECLARE @fieldCount int;
WITH TildeCounts AS (
SELECT LEN(ALLOCATED_PART_NBR) - LEN(REPLACE(ALLOCATED_PART_NBR, '~', '')) AS TildeCount
FROM TestTable t
UNION ALL
SELECT LEN( ALLOCATED_SALES_ITM) - LEN(REPLACE( ALLOCATED_SALES_ITM, '~', '')) AS TildeCount
FROM TestTable t
UNION ALL
SELECT LEN(ALLOCATED_QTY) - LEN(REPLACE(ALLOCATED_QTY, '~', '')) AS TildeCount
FROM TestTable t
) SELECT @fieldCount = MAX(TildeCount) + 1 FROM TildeCounts;
SELECT t.SOS_ID, a.Element AS [ALLOCATED_PART_NBR], b.Element AS [ALLOCATED_SALES_ITM], c.Element AS [ALLOCATED_QTY]
FROM TestTable t
CROSS APPLY dbo.SplitString(ALLOCATED_PART_NBR, '~', @fieldCount) a
CROSS APPLY dbo.SplitString(ALLOCATED_SALES_ITM, '~', @fieldCount) b
CROSS APPLY dbo.SplitString(ALLOCATED_QTY, '~', @fieldCount) c
WHERE a.ElementID = b.ElementID AND b.ElementID = c.ElementID
这样做首先获得所有字符串中的最大字段数(因此它可以填充较短的字符串)。然后它从表中选择CROSS APPYING函数到每一列,仅过滤所有ID匹配的行(排队)。
答案 1 :(得分:1)
将字符串转换为xml,然后从每个节点中选择第n个节点。
DECLARE @max_field_count int = 6;
SELECT
SOS_ID
,ALLOCATED_PART_NBR = CAST(N'<a>'+REPLACE(ALLOCATED_PART_NBR ,'~','</a><a>')+'</a>' AS XML).query('(a)[sql:column("i")]').value('.','varchar(max)')
,ALLOCATED_SALES_ITM = CAST(N'<a>'+REPLACE(ALLOCATED_SALES_ITM,'~','</a><a>')+'</a>' AS XML).query('(a)[sql:column("i")]').value('.','varchar(max)')
,ALLOCATED_QTY = CAST(N'<a>'+REPLACE(ALLOCATED_QTY ,'~','</a><a>')+'</a>' AS XML).query('(a)[sql:column("i")]').value('.','varchar(max)')
FROM MyTable
CROSS JOIN (SELECT TOP (@max_field_count) ROW_NUMBER() OVER(ORDER BY (SELECT 1)) FROM master.dbo.spt_values) n(i)