SQL中如何将单行数据拆分成多行?
Posted
技术标签:
【中文标题】SQL中如何将单行数据拆分成多行?【英文标题】:How to split the data in a single row into multiple rows in SQL? 【发布时间】:2021-08-10 09:43:53 【问题描述】:我有一个格式如下的表格
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。 有可能吗?
【问题讨论】:
您的 SQL Server 版本是多少?这是一个有效的 JSON 数组,因此您可以尝试使用OPENJSON
解析它。
我实际上想将这些数据输入到 powerbi 中。所以,我需要制定一个有效的查询。
请注明locationid列的数据类型是什么,你的sql server是什么版本。
locationID 列的类型为 NVarchar。 SQL Server 版本是 2014,但没关系,因为我将使用 Power-Bi 应用程序中的查询。
好吧,SELECT v.ProjectID, j.LocationID FROM (VALUES (1, '[1,2,3,4]'), (2, '[2,3]')) v (ProjectID, LocationID) OUTER APPLY OPENJSON (v.LocationID) WITH (LocationID int '$') j
是一个选项。
【参考方案1】:
如果 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
【讨论】:
对不起,但我没有创建或更改表的规定。我需要使用 select 子句以上述格式获取数据。 由于您的 sql server 版本是 2014,因此 string_split() 或 openjson() 都不起作用。让我找点别的。 你能告诉我如何在更新的版本中完成吗?我会尝试,因为它将被移动到 Azure SQL 数据库 id 所做的将适用于 2016 年和病房版本。现在修改我对 2014 年的回答。 WHERE b '' 我在这部分查询中遇到错误。【参考方案2】:在 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 是一个 dbfiddle。
特别是,锚部分只是设置数据——它不从字符串中提取任何元素。所以,所有的逻辑都在递归部分,我觉得更容易维护。
【讨论】:
【参考方案3】:我使用了 STRING_SPLIT(),它是一个表值函数,支持 SQL Server 2016 及更高版本。您需要在此函数中提供格式化字符串并使用 cross apply 来连接并生成所需的输出。
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] , ',');
【讨论】:
【参考方案4】:感谢大家帮助我。此解决方案适用于我的场景。
从项目中选择 projectID,locationid_list CROSS APPLY OPENJSON(locationid, '$') WITH (locationid_list int '$')
【讨论】:
以上是关于SQL中如何将单行数据拆分成多行?的主要内容,如果未能解决你的问题,请参考以下文章