【问题标题】:How to split the data in a single row into multiple rows in SQL?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 是一个选项。

标签: sql sql-server tsql sql-server-2014


【解决方案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 '$')

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-14
        • 1970-01-01
        • 1970-01-01
        • 2023-04-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多