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

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

【讨论】:

对不起,但我没有创建或更改表的规定。我需要使用 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中如何将单行数据拆分成多行?的主要内容,如果未能解决你的问题,请参考以下文章

oracle单行多列,拆分成多行

sql如何把行拆分为几行

sql一个字段内有分隔符如何拆分成多行

sql一行拆分多行记录

将多行连接成单行并计算 SQL Server 中连接的行数

如何将多行合并为表中的单行