我有一个长字符串的列。数据需要拆分成列,并且可变长度的字符串并不总是相同的列数。不完全确定如何做到这一点,所以在这里寻找一些建议。
让我说我有这个字符串:
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定义。
感谢您对制作此动态
的任何想法安德鲁
答案 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,但是它通过文本文件使用往返。
该方法使用以下步骤:
~
符号分隔符这种方法的主要好处是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