拆分可变长度的字符串,可变分隔符
Split string of variable length, variable delimiters
阅读 here 提出的问题,但我的问题有点复杂。
我有一个长度可变的字符串,分隔符有时可以是两个破折号,有时可以只是一个。假设在我的 table 中,我要分解的数据存储在这样的单个列中:
+ -----------------------------------------+
| Category |
+------------------------------------------+
| Zoo - Animals - Lions |
| Zoo - Personnel |
| Zoo - Operating Costs - Power / Cooling |
+------------------------------------------+
但我想将该单列中的数据字符串输出到三个单独的列中,如下所示:
+----------+--------------------+-----------------+
| Location | Category | Sub-Category |
+----------+--------------------+-----------------+
| Zoo | Animals | Lions |
| Zoo | Personnel | |
| Zoo | Operating Costs | Power / Cooling |
+----------+--------------------+-----------------+
希望得到一些指导,因为我在 Google 上找到的示例似乎比这更简单。
有点破解,但它有效:
DECLARE @t TABLE (Category VARCHAR(255))
INSERT @t (Category)
VALUES ('Zoo - Animals - Lions'),('Zoo - Personnel'),('Zoo - Operating Costs - Power / Cooling')
;WITH split_vals AS (
SELECT Category AS Cat,TRIM(Value) AS Value,ROW_NUMBER() OVER (PARTITION BY Category ORDER BY Category) AS RowNum
FROM @t
CROSS APPLY STRING_SPLIT(Category,'-')
), cols AS (
SELECT
Cat,
CASE WHEN RowNum = 1 THEN Value END AS Location,
CASE WHEN RowNum = 2 THEN Value END AS Category,
CASE WHEN RowNum = 3 THEN Value END AS [Sub-Category]
FROM split_vals
)
SELECT STRING_AGG(Location, '') AS Location,
STRING_AGG(Category, '') AS Category,
STRING_AGG([Sub-Category], '') AS [Sub-Category]
FROM cols
GROUP BY Cat;
这是一个只使用字符串函数的解决方案:
select
left(
category,
charindex('-', category) - 2
) location,
substring(
category,
charindex('-', category) + 2,
len(category) - charindex('-', category, charindex('-', category) + 1)
) category,
case when charindex('-', category, charindex('-', category) + 1) > 0
then right(category, charindex('-', reverse(category)) - 2)
end sub_category
from t
location | category | sub_category
:------- | :--------------- | :--------------
Zoo | Animal | Lions
Zoo | Personnel | null
Zoo | Operating Costs | Power / Cooling
您还可以使用字符串拆分器。这是适用于您的版本的优秀版本。 DelimitedSplit8K
现在我们需要一些示例数据。
declare @Something table
(
Category varchar(100)
)
insert @Something values
('Zoo - Animals - Lions')
, ('Zoo - Personnel')
, ('Zoo - Operating Costs - Power / Cooling')
现在我们有了一个函数和样本数据,它的代码非常漂亮和整洁。
select s.Category
, Location = max(case when x.ItemNumber = 1 then Item end)
, Category = max(case when x.ItemNumber = 2 then Item end)
, SubCategory = max(case when x.ItemNumber = 3 then Item end)
from @Something s
cross apply dbo.DelimitedSplit8K(s.Category, '-') x
group by s.Category
这将 return:
Category |Location|Category |SubCategory
Zoo - Animals - Lions |Zoo |Animals |Lions
Zoo - Operating Costs - Power / Cooling |Zoo |Operating Costs|Power / Cooling
Zoo - Personnel |Zoo |Personnel |NULL
您用 [sql-server-2017]
标记了它。这意味着,您可以使用 JSON-support(这是在 v2016 中引入的)。
目前JSON是最好的内置位置和类型安全字符串拆分方法:
模拟您的问题的模型
DECLARE @mockup TABLE (ID INT IDENTITY, Category VARCHAR(MAX))
INSERT INTO @mockup (Category)
VALUES ('Zoo - Animals - Lions')
,('Zoo - Personnel')
,('Zoo - Operating Costs - Power / Cooling');
--查询
SELECT t.ID
,A.[Location]
,A.Category
,A.subCategory
FROM @mockup t
CROSS APPLY OPENJSON(CONCAT('[["',REPLACE(t.Category,'-','","'),'"]]'))
WITH ([Location] VARCHAR(MAX) '$[0]'
,Category VARCHAR(MAX) '$[1]'
,SubCategory VARCHAR(MAX) '$[2]') A;
结果(可能需要一些 TRIM()
ing)
ID Location Category subCategory
1 Zoo Animals Lions
2 Zoo Personnel NULL
3 Zoo Operating Costs Power / Cooling
简而言之:
我们使用一些简单的字符串操作将您的字符串转换为 JSON 数组:
a b c => [["a","b","c"]]
现在我们可以将 OPENJSON()
与 WITH
子句一起用于 return 每个片段的位置和固定类型。
阅读 here 提出的问题,但我的问题有点复杂。
我有一个长度可变的字符串,分隔符有时可以是两个破折号,有时可以只是一个。假设在我的 table 中,我要分解的数据存储在这样的单个列中:
+ -----------------------------------------+
| Category |
+------------------------------------------+
| Zoo - Animals - Lions |
| Zoo - Personnel |
| Zoo - Operating Costs - Power / Cooling |
+------------------------------------------+
但我想将该单列中的数据字符串输出到三个单独的列中,如下所示:
+----------+--------------------+-----------------+
| Location | Category | Sub-Category |
+----------+--------------------+-----------------+
| Zoo | Animals | Lions |
| Zoo | Personnel | |
| Zoo | Operating Costs | Power / Cooling |
+----------+--------------------+-----------------+
希望得到一些指导,因为我在 Google 上找到的示例似乎比这更简单。
有点破解,但它有效:
DECLARE @t TABLE (Category VARCHAR(255))
INSERT @t (Category)
VALUES ('Zoo - Animals - Lions'),('Zoo - Personnel'),('Zoo - Operating Costs - Power / Cooling')
;WITH split_vals AS (
SELECT Category AS Cat,TRIM(Value) AS Value,ROW_NUMBER() OVER (PARTITION BY Category ORDER BY Category) AS RowNum
FROM @t
CROSS APPLY STRING_SPLIT(Category,'-')
), cols AS (
SELECT
Cat,
CASE WHEN RowNum = 1 THEN Value END AS Location,
CASE WHEN RowNum = 2 THEN Value END AS Category,
CASE WHEN RowNum = 3 THEN Value END AS [Sub-Category]
FROM split_vals
)
SELECT STRING_AGG(Location, '') AS Location,
STRING_AGG(Category, '') AS Category,
STRING_AGG([Sub-Category], '') AS [Sub-Category]
FROM cols
GROUP BY Cat;
这是一个只使用字符串函数的解决方案:
select
left(
category,
charindex('-', category) - 2
) location,
substring(
category,
charindex('-', category) + 2,
len(category) - charindex('-', category, charindex('-', category) + 1)
) category,
case when charindex('-', category, charindex('-', category) + 1) > 0
then right(category, charindex('-', reverse(category)) - 2)
end sub_category
from t
location | category | sub_category :------- | :--------------- | :-------------- Zoo | Animal | Lions Zoo | Personnel | null Zoo | Operating Costs | Power / Cooling
您还可以使用字符串拆分器。这是适用于您的版本的优秀版本。 DelimitedSplit8K
现在我们需要一些示例数据。
declare @Something table
(
Category varchar(100)
)
insert @Something values
('Zoo - Animals - Lions')
, ('Zoo - Personnel')
, ('Zoo - Operating Costs - Power / Cooling')
现在我们有了一个函数和样本数据,它的代码非常漂亮和整洁。
select s.Category
, Location = max(case when x.ItemNumber = 1 then Item end)
, Category = max(case when x.ItemNumber = 2 then Item end)
, SubCategory = max(case when x.ItemNumber = 3 then Item end)
from @Something s
cross apply dbo.DelimitedSplit8K(s.Category, '-') x
group by s.Category
这将 return:
Category |Location|Category |SubCategory
Zoo - Animals - Lions |Zoo |Animals |Lions
Zoo - Operating Costs - Power / Cooling |Zoo |Operating Costs|Power / Cooling
Zoo - Personnel |Zoo |Personnel |NULL
您用 [sql-server-2017]
标记了它。这意味着,您可以使用 JSON-support(这是在 v2016 中引入的)。
目前JSON是最好的内置位置和类型安全字符串拆分方法:
模拟您的问题的模型
DECLARE @mockup TABLE (ID INT IDENTITY, Category VARCHAR(MAX))
INSERT INTO @mockup (Category)
VALUES ('Zoo - Animals - Lions')
,('Zoo - Personnel')
,('Zoo - Operating Costs - Power / Cooling');
--查询
SELECT t.ID
,A.[Location]
,A.Category
,A.subCategory
FROM @mockup t
CROSS APPLY OPENJSON(CONCAT('[["',REPLACE(t.Category,'-','","'),'"]]'))
WITH ([Location] VARCHAR(MAX) '$[0]'
,Category VARCHAR(MAX) '$[1]'
,SubCategory VARCHAR(MAX) '$[2]') A;
结果(可能需要一些 TRIM()
ing)
ID Location Category subCategory
1 Zoo Animals Lions
2 Zoo Personnel NULL
3 Zoo Operating Costs Power / Cooling
简而言之:
我们使用一些简单的字符串操作将您的字符串转换为 JSON 数组:
a b c => [["a","b","c"]]
现在我们可以将 OPENJSON()
与 WITH
子句一起用于 return 每个片段的位置和固定类型。