如何从列中提取值并在另一列中更新结果

时间:2018-08-30 15:12:28

标签: sql sql-server split

我有这张桌子:

CREATE TABLE MyTable (
    IdDate int,
    FullDate varchar(255)
);

insert into MyTable (IdDate,FullDate)
VALUES (0, 'Nº1 (26) - Friday 4, January 2014'),
       (0,'Nº2 (64) - Monday 10, February 2015')

我想从FullDate中提取如下内容:

1 2014 01 04
2 2015 02 10

1st number is extracted from Nº1
2nd number is extracted from Year
3rd number is extracted from Month (convert January to 01)
4th number is extracted from day (if day < 10, add 0 at the beginning: 01,02... )

并更新在第一列IdDate中提取的新值

我的最终结果应该是:

IdDate        FullDate
120140104     Nº1 (26) - Friday 4, January 2014
220150210     Nº2 (64) - Monday 10, February 2015

4 个答案:

答案 0 :(得分:3)

如果对助手表值函数开放:

示例

Declare @YourTable table (IdDate int,FullDate varchar(max))
Insert Into @YourTable values
 (0,'Nº1 (26) - Friday 4, January 2014')
,(0,'Nº2 (64) - Monday 10, February 2015')

Update A
   set IdDate = substring(Pos1,3,10)
              + try_convert(varchar(10),try_convert(date,Pos6+' '+Pos5+' '+Pos7),112)
 From  @YourTable A
 Cross Apply [dbo].[tvf-Str-Parse-Row](FullDate,' ') B

返回

IDDate      FullDate
120140104   Nº1 (26) - Friday 4, January 2014
220150210   Nº2 (64) - Monday 10, February 2015

如果有助于可视化,TVF将返回

enter image description here

感兴趣的功能

CREATE FUNCTION [dbo].[tvf-Str-Parse-Row] (@String varchar(max),@Delimiter varchar(10))
Returns Table 
As
Return (
    Select Pos1 = ltrim(rtrim(xDim.value('/x[1]','varchar(max)')))
          ,Pos2 = ltrim(rtrim(xDim.value('/x[2]','varchar(max)')))
          ,Pos3 = ltrim(rtrim(xDim.value('/x[3]','varchar(max)')))
          ,Pos4 = ltrim(rtrim(xDim.value('/x[4]','varchar(max)')))
          ,Pos5 = ltrim(rtrim(xDim.value('/x[5]','varchar(max)')))
          ,Pos6 = ltrim(rtrim(xDim.value('/x[6]','varchar(max)')))
          ,Pos7 = ltrim(rtrim(xDim.value('/x[7]','varchar(max)')))
          ,Pos8 = ltrim(rtrim(xDim.value('/x[8]','varchar(max)')))
          ,Pos9 = ltrim(rtrim(xDim.value('/x[9]','varchar(max)')))
    From  (Select Cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml) as xDim) as A 
)

或者没有功能

Update A
   set IdDate = substring(Pos1,3,10)
              + try_convert(varchar(10),try_convert(date,Pos6+' '+Pos5+' '+Pos7),112)
 From  @YourTable A
 Cross Apply (
                Select Pos1 = ltrim(rtrim(xDim.value('/x[1]','varchar(max)')))
                      ,Pos2 = ltrim(rtrim(xDim.value('/x[2]','varchar(max)')))
                      ,Pos3 = ltrim(rtrim(xDim.value('/x[3]','varchar(max)')))
                      ,Pos4 = ltrim(rtrim(xDim.value('/x[4]','varchar(max)')))
                      ,Pos5 = ltrim(rtrim(xDim.value('/x[5]','varchar(max)')))
                      ,Pos6 = ltrim(rtrim(xDim.value('/x[6]','varchar(max)')))
                      ,Pos7 = ltrim(rtrim(xDim.value('/x[7]','varchar(max)')))
                From  (Select Cast('<x>' + replace((Select replace(FullDate,' ','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml) as xDim) as A 
             ) B
  

编辑

这是Shawn的 cleaner 解决方案的扩展版本

Update @YourTable 
   set IdDate = substring(left(FullDate,charindex(' ',FullDate)-1),3,25)
               +try_convert(varchar(10),try_convert(date,replace(substring(FullDate, charindex(',', FullDate) - 2, 100), ',', '')),112)


Select * from @YourTable

答案 1 :(得分:2)

这将提取一个日期值。它只是查找逗号,备份一些字符并获取日期,剥离逗号并将其视为军事日期。

select convert(date,  
   replace(substring(FullDate, charindex(',', FullDate) - 2, 100), ',', ''), 106)

使用format()或日期样式112以所需的方式获取输出。第一个字符显然只是substring(FullDate, 3, 1),因此只需将其附加到前面即可。

答案 2 :(得分:1)

如果您不必使用像John posted这样的函数(这就是我要做的事情)就可以解决这个问题,则可以深入研究并开始一个字符串函数的噩梦之路。挑战在于t-sql在字符串操作方面并不出色。

这似乎适用于您提供的示例数据。请注意,如果您的数据无法转换为日期,则将失败。

update MyTable
set IdDate = substring(FullDate, 3, CHARINDEX(' ', FullDate) - 3)
    + Right(FullDate, 4)
    + right('0' + convert(varchar(2), datepart(month, convert(date, replace(substring(substring(FullDate, charindex('-', FullDate) + 2, len(FullDate)), charindex(' ', substring(FullDate, charindex('-', FullDate) + 2, len(FullDate))) + 1, len(FullDate)), ',', '')))), 2)
    + right('0' + convert(varchar(2), datepart(day, convert(date, replace(substring(substring(FullDate, charindex('-', FullDate) + 2, len(FullDate)), charindex(' ', substring(FullDate, charindex('-', FullDate) + 2, len(FullDate))) + 1, len(FullDate)), ',', '')))), 2)

select * from MyTable

然后去问决定像这样存储数据的人为什么这么做?这根本不是处理数据的方法。

答案 3 :(得分:0)

1st number is extracted from Nº1
2nd number is extracted from Year
3rd number is extracted from Month (convert January to 01)
4th number is extracted from day (if day < 10, add 0 at the beginning: 01,02... )

使用SQL Server's string functions执行以下操作

  1. 获取及其后的第一个空格之间的字符。
  2. 获取最后4个字符
  3. 使用CASE表达式根据喜欢字符串的月份名称生成月份号
  4. 获取逗号前的2个字符,并用0替换其中的空白字符。

并将这四个值连接在一起。