首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将字符串中的数据拆分成列

将字符串中的数据拆分成列
EN

Stack Overflow用户
提问于 2017-03-15 00:26:31
回答 2查看 121关注 0票数 0

我有一个长字符串的列。数据需要拆分成列,并且有不同长度的字符串,它们的列数并不总是相同。不太确定如何做到这一点,所以在这里寻求一些建议。

假设我有这个字符串:

VS5~MedCond1~35.4|VS4~MedCond2~16|VS1~MedCond3~155|VS2~MedCond4~70|SPO2~MedCond5~100|VS3~MedCond6~64|FiO2~MedCond7~21|MAP~MedCond8~98|

在某些情况下,字符串可能不会包含所有的医疗条件,只是其中的一部分。

我需要将列名分成几列,其中列名在tild之间,即MedCond1,值将是tild右侧但在管道之前的值,最后如下所示:

代码语言:javascript
运行
复制
  MedCond1 MedCond2 MedCond3 MedCond4 MedCond5 MedCond6 MedCond7 MedCond8
  ======== ======== ======== ======== ======== ======== ======== ========
  35.1      24       110       64      100      88       21       79

我需要对大表中的许多行执行此操作,正如我所说的,并不是所有的列都存在,但它们不会是不同的名称,您可能已经完成了med 1- 8,然后在另一个集合中具有med 3,4,7。

下面是我创建的一个查询,它是我想要的,但不是动态的,所以它通过字符串的一些额外部分来提取值

代码语言:javascript
运行
复制
select MainCol, case when charindex('MedCond1', MainCol) > 0 then 
substring(MainCol, charindex('MedCond1', MainCol) + 9, 4) end as [MedCond1] 
from MedTable

将会返回

代码语言:javascript
运行
复制
MedCond1
========
35.3
40.2
33.6
33|V  <--- Problem

正如您所看到的,由于charindex数字的硬编码,有时会使用字符串的附加部分来提取数字值。值的长度有时为4个字符,带小数位,有时为2个字符,不带小数位。我想让它具有动态性。管道定义了我需要的数据的结尾,起始是由列名称末尾的tild定义的。

感谢您对此进行动态化的任何想法

安德鲁

EN

回答 2

Stack Overflow用户

发布于 2017-03-15 20:48:49

这些数据看起来就像一个表本身。它可以作为xml存储在SQL Server中。SQL Server支持xml字段并允许对其进行查询。实际上,您可以尝试将此字符串转换为XML,然后尝试查询它:

代码语言:javascript
运行
复制
declare @medTable table (item nvarchar(2000))
insert into @medTable
values ('VS5~MedCond1~35.4|VS4~MedCond2~16|VS1~MedCond3~155|VS2~MedCond4~70|SPO2~MedCond5~100|VS3~MedCond6~64|FiO2~MedCond7~21|MAP~MedCond8~98|');

-- Step 1: Replace `|` with <item> tags and `~` with `tag` tags
-- This will return an xml value for each medTable row
with items as (
    select xmlField= cast('<item><tag>' 
                           + replace( 
                                     replace(item,'|','</tag></item><item><tag>'),
                                    '~','</tag><tag>' )
                           + '</tag></item>' as xml) 
    from @medTable 
)
-- Step 2: Select different tags and display them as fields
select 
    y.item.value('(tag/text())[1]','nvarchar(20)'),
    y.item.value('(tag/text())[2]','nvarchar(20)'),
    y.item.value('(tag/text())[3]','nvarchar(20)')
from items outer apply xmlField.nodes('item') as y(item)

结果是:

代码语言:javascript
运行
复制
-------------------- -------------------- -------
VS5                  MedCond1             35.4
VS4                  MedCond2             16
VS1                  MedCond3             155
VS2                  MedCond4             70
SPO2                 MedCond5             100
VS3                  MedCond6             64
FiO2                 MedCond7             21
MAP                  MedCond8             98
NULL                 NULL                 NULL

不过,最好在加载数据时执行此转换。例如,在C#或SSIS中进行替换并将完整的XML值存储在数据库中会更容易。

您还可以修改此查询,以生成XML值并将其存储在数据库中:

代码语言:javascript
运行
复制
declare @medTable2 table (xmlField xml)

with items as (
    select xmlField= cast('<item><tag>' + replace(replace(item,'|','</tag></item><item><tag>'),'~','</tag><tag>' ) + '</tag></item>' as xml) 
    from @medTable 
)
insert into @medTable2
select items.xmlField
from items 

-- Query the new table from now on 
select 
    y.item.value('(tag/text())[1]','nvarchar(20)'),
    y.item.value('(tag/text())[2]','nvarchar(20)'),
    y.item.value('(tag/text())[3]','nvarchar(20)')
from @medTable2 outer apply xmlField.nodes('item') as y(item)
票数 1
EN

Stack Overflow用户

发布于 2017-03-15 20:44:28

好的,让我来试一试。我概述的解决方案不会是纯粹的SQL Server,但是,它通过文本文件使用往返。

该方法使用以下步骤:

将由竖线符号分隔的数据(为每行输入创建多行输出)将数据从SQL Server返回到文本文件,然后在代字号符号分隔符上将数据返回到列中

  • Pivot

  • Round-trip data

  • Separate

  • Pivot ~

这种方法的主要优点是unpivot操作,它允许您在缺少等效行的情况下自然地处理缺少的列,如MedCond2。它还消除了几乎所有的字符串操作,除了下面步骤1中的一个REPLACE函数。

给定单行内容,如下所示:

代码语言:javascript
运行
复制
VS5~MedCond1~35.4|VS4~MedCond2~16|VS1~MedCond3~155|VS2~MedCond4~70|SPO2~MedCond5~100|VS3~MedCond6~64|FiO2~MedCond7~21|MAP~MedCond8~98| 

取消旋转步骤1():查找管道符号的所有实例,并将其替换为换行符。因此,对于单个输入行,REPLACE(column, '|', CHAR(13))将为您提供以下文本行(即,单个数据库行中的多行文本):

代码语言:javascript
运行
复制
VS5~MedCond1~35.4
VS4~MedCond2~16
VS1~MedCond3~155
VS2~MedCond4~70
SPO2~MedCond5~100
VS3~MedCond6~64
FiO2~MedCond7~21
MAP~MedCond8~98

步骤2(往返):使用您选择的工具(SSIS、SQLCMD等)将上述输出写入一个文本文件。并确保定义的换行符与步骤1中的REPLACE命令中使用的换行符相同。

此步骤的目的是将同一行中的多条线路与不同行中的其他线路连接起来。

请注意,可以通过将步骤2和3的行分隔符定义为管道符号来消除步骤1。我添加了额外的步骤1,使用换行符只是为了使其更容易理解和调试。

步骤3(分栏):使用相同的工具将文本文件重新导入SQL Server,并将列分隔符定义为代字号~符号,行分隔符的定义与步骤1/2相同。

代码语言:javascript
运行
复制
ColA   MedCondTitle  MedCondValue 
------ ------------- ------------- 
VS5    MedCond1      35.4
VS4    MedCond2      16
VS1    MedCond3      155
VS2    MedCond4      70
SPO2   MedCond5      100
VS3    MedCond6      64
FiO2   MedCond7      21
MAP    MedCond8      98

步骤4(透视):现在您已经有了将行旋转为列的简单步骤,这可以通过以下形式的语句来实现:

代码语言:javascript
运行
复制
SUM(CASE WHEN MedCondTitle='MedCond1' THEN MedCondValue ELSE 0) as MedCond1 
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42791402

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档