将数据从字符串拆分为

时间:2017-03-14 16:26:31

标签: sql-server string split sql-server-2012

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

让我说我有这个字符串:

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右边的值,但在管道之前,最终会像这样:

  MedCond1 MedCond2 MedCond3 MedCond4 MedCond5 MedCond6 MedCond7 MedCond8
  ======== ======== ======== ======== ======== ======== ======== ========
  35.1      24       110       64      100      88       21       79

我需要为大型表中的很多行执行此操作,并且我说并非所有列都始终存在但它们不会是不同的名称,您可能有med cond 1- 8,然后在另一组中有med cond 3,4,7。

这是我创建的一个查询,它是我想要的但不是动态的,所以它是用字符串的一些额外位来获取值

select MainCol, case when charindex('MedCond1', MainCol) > 0 then 
substring(MainCol, charindex('MedCond1', MainCol) + 9, 4) end as [MedCond1] 
from MedTable

将返回

MedCond1
========
35.3
40.2
33.6
33|V  <--- Problem

正如您所看到的,由于charindex数字的硬编码,有时会使用字符串的其他部分来获取数值。该值有时为4个字符长,带小数位,有时为2个长,没有小数位。我想让这个充满活力。管道定义了我需要的数据的结尾,并且开始由列名末尾的tild定义。

感谢您对制作此动态

的任何想法

安德鲁

2 个答案:

答案 0 :(得分:1)

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

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)

结果是:

-------------------- -------------------- -------
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值并将其存储在数据库中:

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 :(得分:0)

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

该方法使用以下步骤:

  1. Unpivot 由管道符号分隔的数据(为每行输入创建多行输出)
  2. 往返从SQL Server到文本文件并返回
  3. 的数据
  4. 将数据分隔到代字号~符号分隔符
  5. 上的列中
  6. 将数据转换回
  7. 数据

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

    给出单行的内容,如下所示:

    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))将为单个输入行提供以下文本行(即单个数据库行中的多行文本):

    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和步骤2定义行分隔符来消除步骤1。 3作为管道符号。我已经使用换行符添加了第1步,以便更容易理解和调试。

    步骤3(单独的列):使用相同的工具将文本文件导回SQL Server,并将列分隔符定义为波浪号~符号,行分隔符与步骤1/2。

    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(数据透视):现在您可以轻松地将行旋转到列,这可以通过表单声明来实现:

    SUM(CASE WHEN MedCondTitle='MedCond1' THEN MedCondValue ELSE 0) as MedCond1