如何在SQL中将单行数据拆分为多行?
How to split the data in a single row into multiple rows in SQL?
我有一个table格式如下
ProjectID LocationID
1 [1,2,3,4]
2 [2,3]
我可以像下面这样将 LocationID 列中的数据拆分为多行吗?
ProjectID LocationID
1 1
1 2
1 3
1 4
2 2
2 3
我只需要使用 SQL 将数据加载到 Power-Bi。
可能吗?
如果 locationID 的数据类型是 varchar 那么:
create table projects (ProjectID int, LocationID varchar(50));
insert into projects values(1, '[1,2,3,4]');
insert into projects values(2, '[2,3]');
查询:
select projectid, value
from projects
CROSS APPLY STRING_SPLIT(replace(replace(locationid,'[',''),']',''),',')
输出:
projectid
value
1
1
1
2
1
3
1
4
2
2
2
3
dbhere
SQL Server 2014
的解决方案
create table projects (ProjectID int, LocationID nvarchar(max));
insert into projects values(1, '[1,2,3,4]');
insert into projects values(2, '[2,3]');
查询:
WITH tmp AS
(
SELECT
ProjectID,
LEFT(replace(replace(locationid,'[',''),']',''), CHARINDEX(',', replace(replace(locationid,'[',''),']','') + ',') - 1) LocationID,
STUFF(replace(replace(locationid,'[',''),']',''), 1, CHARINDEX(',', replace(replace(locationid,'[',''),']','') + ','), '') b
FROM projects
UNION all
SELECT
ProjectID,
LEFT(b, CHARINDEX(',', b + ',') - 1),
STUFF(b, 1, CHARINDEX(',', b + ','), '')
FROM tmp
WHERE
b > ''
)
SELECT
ProjectID, LocationID
FROM tmp
ORDER BY projectid
输出:
ProjectID
LocationID
1
1
1
2
1
3
1
4
2
2
2
3
dbhere
在 SQL Server 2014 中,您可以使用递归 CTE——Kazi 也提出了这一点。我认为这是一个稍微简单的版本:
with cte as (
select projectId, convert(varchar(max), null) as locationid,
convert(varchar(max), substring(LocationId, 2, len(locationId) - 2)) + ',' as rest
from t
union all
select projectId,
left(rest, charindex(',', rest) - 1),
stuff(rest, 1, charindex(',', rest), '')
from cte
where rest <> ''
)
select projectid, locationid
from cte
where locationid is not null;
Here 是一个 db<>fiddle.
特别是,锚点部分只是设置数据——它不会从字符串中提取任何元素。所以,所有的逻辑都在递归部分,我觉得更容易维护。
我使用了 STRING_SPLIT(),这是一个 table 值函数,支持 SQL 服务器 2016 及更高版本。您需要将格式化的字符串提供给此函数并使用交叉应用来连接并生成所需的输出。
SELECT
projectID
, REPLACE(REPLACE(locationId,'[',''),']','') as [locationid]
INTO #temp_table
FROM split_string -- Add your table name here
SELECT
projectID
,VALUE [locationid]
FROM #temp_table
CROSS APPLY STRING_SPLIT( [locationid] , ',');
感谢大家帮助我。此解决方案适用于我的场景。
Select 项目 ID,locationid_list 来自项目
交叉应用 OPENJSON(locationid, '$') WITH (locationid_list int '$')
我有一个table格式如下
ProjectID LocationID
1 [1,2,3,4]
2 [2,3]
我可以像下面这样将 LocationID 列中的数据拆分为多行吗?
ProjectID LocationID
1 1
1 2
1 3
1 4
2 2
2 3
我只需要使用 SQL 将数据加载到 Power-Bi。 可能吗?
如果 locationID 的数据类型是 varchar 那么:
create table projects (ProjectID int, LocationID varchar(50));
insert into projects values(1, '[1,2,3,4]');
insert into projects values(2, '[2,3]');
查询:
select projectid, value
from projects
CROSS APPLY STRING_SPLIT(replace(replace(locationid,'[',''),']',''),',')
输出:
projectid | value |
---|---|
1 | 1 |
1 | 2 |
1 | 3 |
1 | 4 |
2 | 2 |
2 | 3 |
db
SQL Server 2014
的解决方案 create table projects (ProjectID int, LocationID nvarchar(max));
insert into projects values(1, '[1,2,3,4]');
insert into projects values(2, '[2,3]');
查询:
WITH tmp AS
(
SELECT
ProjectID,
LEFT(replace(replace(locationid,'[',''),']',''), CHARINDEX(',', replace(replace(locationid,'[',''),']','') + ',') - 1) LocationID,
STUFF(replace(replace(locationid,'[',''),']',''), 1, CHARINDEX(',', replace(replace(locationid,'[',''),']','') + ','), '') b
FROM projects
UNION all
SELECT
ProjectID,
LEFT(b, CHARINDEX(',', b + ',') - 1),
STUFF(b, 1, CHARINDEX(',', b + ','), '')
FROM tmp
WHERE
b > ''
)
SELECT
ProjectID, LocationID
FROM tmp
ORDER BY projectid
输出:
ProjectID | LocationID |
---|---|
1 | 1 |
1 | 2 |
1 | 3 |
1 | 4 |
2 | 2 |
2 | 3 |
db
在 SQL Server 2014 中,您可以使用递归 CTE——Kazi 也提出了这一点。我认为这是一个稍微简单的版本:
with cte as (
select projectId, convert(varchar(max), null) as locationid,
convert(varchar(max), substring(LocationId, 2, len(locationId) - 2)) + ',' as rest
from t
union all
select projectId,
left(rest, charindex(',', rest) - 1),
stuff(rest, 1, charindex(',', rest), '')
from cte
where rest <> ''
)
select projectid, locationid
from cte
where locationid is not null;
Here 是一个 db<>fiddle.
特别是,锚点部分只是设置数据——它不会从字符串中提取任何元素。所以,所有的逻辑都在递归部分,我觉得更容易维护。
我使用了 STRING_SPLIT(),这是一个 table 值函数,支持 SQL 服务器 2016 及更高版本。您需要将格式化的字符串提供给此函数并使用交叉应用来连接并生成所需的输出。
SELECT
projectID
, REPLACE(REPLACE(locationId,'[',''),']','') as [locationid]
INTO #temp_table
FROM split_string -- Add your table name here
SELECT
projectID
,VALUE [locationid]
FROM #temp_table
CROSS APPLY STRING_SPLIT( [locationid] , ',');
感谢大家帮助我。此解决方案适用于我的场景。
Select 项目 ID,locationid_list 来自项目 交叉应用 OPENJSON(locationid, '$') WITH (locationid_list int '$')