SQL 如何 return 基于逗号分隔的其他子字符串位置的列值
SQL How to return column value based in other substring position delimited by commas
我的第一个post!我希望你能帮助我 :)
我在 SQL 2017 年工作,我有一个 table 这样的:
+----+------------------+------------------+
| ID | Col1 | Col2 |
+-----+------------------+------------------+
| 110 | 450,2,50,110,600 | 3,45,30,901,1001 |
| 250 | 2,250,300,1 | 1,33,540,900 |
| 45 | 1,45,320 | 200,444,600 |
+-----+------------------+------------------+
逻辑是在 Col1 中找到 ID 位置,return 根据该位置找到 Col2 中的子字符串。
示例:
ID 110 匹配 Col1 中的第 4 个位置,因此应该 return Col2 中的 901 值。
ID 250 匹配 Col1 中的第 2 个位置,因此应该 return Col2 中的 33 值。
ID 45 匹配 Col1 中的第二个位置,因此应该 return Col2 中的 400 值。
我试了很多次都没有成功,可能是方向错了
你能帮忙解决一下吗?
我想要的输出是 Col2 的特定值。
谢谢!
对于 SQL Server 2016+(由于 STRING_SPLIT 支持
,我不打算为更早的版本做一个
DECLARE @BadDesign table (ID int, Col1 varchar(200), Col2 varchar(200));
INSERT @BadDesign VALUES
(110,'450,2,50,110,600', '3,45,30,901,1001'),
(250,'2,250,300,1', '1,33,540,900'),
(45 ,'1,45,320', '200,444,600')
SELECT
*
FROM
@BadDesign B
CROSS APPLY
(SELECT
rn = ROW_NUMBER() OVER (ORDER BY (SELECT 1)), value
FROM
STRING_SPLIT(B.Col1, ',')
) b1
CROSS APPLY
(SELECT
rn = ROW_NUMBER() OVER (ORDER BY (SELECT 1)), value
FROM
STRING_SPLIT(B.Col2, ',')
) b2
WHERE
B.ID = b1.value AND b1.rn = b2.rn
不保证 ROW_NUMBER 与 STRING_SPLIT 输出的一致性。
编辑:还需要 database compatibility to be 130 或更高版本 (SQL Server 2016)
The STRING_SPLIT function is available only under compatibility level
130. If your database compatibility level is lower than 130, SQL Server will not be able to find and execute STRING_SPLIT function. You
can change a compatibility level of database using the following
command: ALTER DATABASE DatabaseName SET COMPATIBILITY_LEVEL = 130
使用自定义字符串拆分函数(此答案使用的是 Aaron Bertrand 编写的函数),因此不限制在 SQL2016+ 上使用
CREATE FUNCTION dbo.SplitStringsOrdered (
@List NVARCHAR(2000)
, @Delimiter NVARCHAR(32)
)
RETURNS TABLE
AS
RETURN (
SELECT
rn = ROW_NUMBER() OVER (ORDER BY Number)
, Item
FROM
(
SELECT
Number
, Item = LTRIM(RTRIM(SUBSTRING(
@List
, Number
, CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number
)
)
)
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY [object_id])
FROM
sys.all_objects
) AS n(Number)
WHERE
Number <= CONVERT(INT, LEN(@List))
AND SUBSTRING(@Delimiter + @List, Number, LEN(@Delimiter)) = @Delimiter
) AS y
);
GO
并修改@gbn 在 his/her 答案中创建的查询 - 这在 SO 上允许吗?
DECLARE @BadDesign table (ID int, Col1 varchar(200), Col2 varchar(200));
INSERT @BadDesign VALUES
(110,'450,2,50,110,600', '3,45,30,901,1001'),
(250,'2,250,300,1', '1,33,540,900'),
(45 ,'1,45,320', '200,444,600')
SELECT
B.*, Col1Value=b1.Item, Cal2Value = B2.Item
FROM
@BadDesign B
CROSS APPLY
(SELECT
rn = ROW_NUMBER() OVER (ORDER BY (SELECT 1)), F.Item
FROM
dbo.SplitStringsOrdered(B.Col1, ',') F
) b1
CROSS APPLY
(SELECT
rn = ROW_NUMBER() OVER (ORDER BY (SELECT 1)), F1.Item
FROM
dbo.SplitStringsOrdered(B.Col2, ',') F1
) b2
WHERE
b1.rn = b2.rn
我的第一个post!我希望你能帮助我 :)
我在 SQL 2017 年工作,我有一个 table 这样的:
+----+------------------+------------------+
| ID | Col1 | Col2 |
+-----+------------------+------------------+
| 110 | 450,2,50,110,600 | 3,45,30,901,1001 |
| 250 | 2,250,300,1 | 1,33,540,900 |
| 45 | 1,45,320 | 200,444,600 |
+-----+------------------+------------------+
逻辑是在 Col1 中找到 ID 位置,return 根据该位置找到 Col2 中的子字符串。
示例:
ID 110 匹配 Col1 中的第 4 个位置,因此应该 return Col2 中的 901 值。
ID 250 匹配 Col1 中的第 2 个位置,因此应该 return Col2 中的 33 值。
ID 45 匹配 Col1 中的第二个位置,因此应该 return Col2 中的 400 值。
我试了很多次都没有成功,可能是方向错了
你能帮忙解决一下吗?
我想要的输出是 Col2 的特定值。
谢谢!
对于 SQL Server 2016+(由于 STRING_SPLIT 支持
,我不打算为更早的版本做一个DECLARE @BadDesign table (ID int, Col1 varchar(200), Col2 varchar(200));
INSERT @BadDesign VALUES
(110,'450,2,50,110,600', '3,45,30,901,1001'),
(250,'2,250,300,1', '1,33,540,900'),
(45 ,'1,45,320', '200,444,600')
SELECT
*
FROM
@BadDesign B
CROSS APPLY
(SELECT
rn = ROW_NUMBER() OVER (ORDER BY (SELECT 1)), value
FROM
STRING_SPLIT(B.Col1, ',')
) b1
CROSS APPLY
(SELECT
rn = ROW_NUMBER() OVER (ORDER BY (SELECT 1)), value
FROM
STRING_SPLIT(B.Col2, ',')
) b2
WHERE
B.ID = b1.value AND b1.rn = b2.rn
不保证 ROW_NUMBER 与 STRING_SPLIT 输出的一致性。
编辑:还需要 database compatibility to be 130 或更高版本 (SQL Server 2016)
The STRING_SPLIT function is available only under compatibility level 130. If your database compatibility level is lower than 130, SQL Server will not be able to find and execute STRING_SPLIT function. You can change a compatibility level of database using the following command: ALTER DATABASE DatabaseName SET COMPATIBILITY_LEVEL = 130
使用自定义字符串拆分函数(此答案使用的是 Aaron Bertrand 编写的函数),因此不限制在 SQL2016+ 上使用
CREATE FUNCTION dbo.SplitStringsOrdered (
@List NVARCHAR(2000)
, @Delimiter NVARCHAR(32)
)
RETURNS TABLE
AS
RETURN (
SELECT
rn = ROW_NUMBER() OVER (ORDER BY Number)
, Item
FROM
(
SELECT
Number
, Item = LTRIM(RTRIM(SUBSTRING(
@List
, Number
, CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number
)
)
)
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY [object_id])
FROM
sys.all_objects
) AS n(Number)
WHERE
Number <= CONVERT(INT, LEN(@List))
AND SUBSTRING(@Delimiter + @List, Number, LEN(@Delimiter)) = @Delimiter
) AS y
);
GO
并修改@gbn 在 his/her 答案中创建的查询 - 这在 SO 上允许吗?
DECLARE @BadDesign table (ID int, Col1 varchar(200), Col2 varchar(200));
INSERT @BadDesign VALUES
(110,'450,2,50,110,600', '3,45,30,901,1001'),
(250,'2,250,300,1', '1,33,540,900'),
(45 ,'1,45,320', '200,444,600')
SELECT
B.*, Col1Value=b1.Item, Cal2Value = B2.Item
FROM
@BadDesign B
CROSS APPLY
(SELECT
rn = ROW_NUMBER() OVER (ORDER BY (SELECT 1)), F.Item
FROM
dbo.SplitStringsOrdered(B.Col1, ',') F
) b1
CROSS APPLY
(SELECT
rn = ROW_NUMBER() OVER (ORDER BY (SELECT 1)), F1.Item
FROM
dbo.SplitStringsOrdered(B.Col2, ',') F1
) b2
WHERE
b1.rn = b2.rn