【问题标题】:Update SQL Data using mask and rules使用掩码和规则更新 SQL 数据
【发布时间】:2014-07-02 09:05:24
【问题描述】:

我在 SQL 2012 的一列中有大约 3000 个条目,目前它们是非结构化的,即

1.1.01.10, 1.1.1.11

我想将数据转换为包含所有单个数字的前导 0 的格式,即

01.01.01.10 等等。

有没有办法通过更新查询来做到这一点?我可以通过导出到 excel 并在那里操作来做到这一点,但如果可能的话,我想避免这种情况。

【问题讨论】:

  • 数据是否总是采用相同的格式,即可能的最大长度字符串是 11.11.11.11?
  • 你能检查一下函数并在你的表中更新它,让我知道它是否工作
  • Shree 没有字符串长度可以运行到 . 之间的三个整数。很不幸
  • Azar - 现在全部尝试一下,然后告诉你,太棒了

标签: sql sql-server-2012 sql-update mask data-masking


【解决方案1】:
Alter function Pad
(
    @str varchar(max) 
)
returns varchar(max)
as
begin
Declare @nstr varchar(max)

while(PATINDEX('%.%',@str)<>0)
  begin
    Set @nstr = isnull(@nstr,'')+case when PATINDEX('%.%',@str) = 2 then '0'+substring(@str,PATINDEX('%.%',@str)-1,1) else SUBSTRING(@str,1,PATINDEX('%.%',@str)-1) end+'.'
    Set @str = case when PATINDEX('%.%',@str) = 2 then stuff(@str,PATINDEX('%.%',@str)-1,2,'') else stuff(@str,1,PATINDEX('%.%',@str),'') end 
  end
Set @nstr = isnull(@nstr,'')+case when len(@str) <> 1 then @str when len(@str) = 1 then '0'+@str else '' end 
return @nstr
end



update t
set num = [dbo].pad(num)
from table t

【讨论】:

    【解决方案2】:

    如果数据总是有 4 个块,则可以一次将它们分解为一个单元。

    With F AS (
      SELECT data
           , rem = substring(data, patindex('%.%', data) + 1, len(data))
           , value1 = substring(data, 1, patindex('%.%', data) - 1)
      FROM   Table1
    ), S AS (
      SELECT data
           , rem = substring(rem, patindex('%.%', rem) + 1, len(rem))
           , value1
           , value2 = substring(rem, 1, patindex('%.%', rem) - 1)
      FROM   F
    ), T AS (
      SELECT data
           , value1
           , value2
           , value3 = substring(rem, 1, patindex('%.%', rem) - 1)
           , value4 = substring(rem, patindex('%.%', rem) + 1, len(rem))
      FROM   S
    )
    UPDATE T SET  
           Data = CONCAT(RIGHT('00' + value1, 2), '.'
                       , RIGHT('00' + value2, 2), '.'
                       , RIGHT('00' + value3, 2), '.'
                       , RIGHT('00' + value4, 2));
    

    SQLFiddle Demo

    查询可以变得更小,但会失去可读性。

    如果块数未知和/或可以在行之间更改,则查询会更复杂并涉及递归CTE

    With Splitter AS (
      -- anchor
      SELECT data
           , rem = substring(data, patindex('%.%', data) + 1, len(data))
           , pos = len(data) - len(replace(data, '.', '')) + 1
           , value = substring(data, 1, patindex('%.%', data) - 1)
           , res = CAST('' as nvarchar(50))
      FROM   Table1
      UNION ALL
      -- runner
      SELECT data
           , rem = substring(rem, patindex('%.%', rem) + 1, len(rem))
           , pos = pos - 1
           , value = substring(rem, 1, patindex('%.%', rem) - 1)
           , res = CAST(res + RIGHT('00' + value, 2) + '.' as nvarchar(50))
      FROM   Splitter
      WHERE  patindex('%.%', rem) > 1
      UNION ALL
      -- stop
      SELECT data
           , rem = ''
           , pos = pos - 1
           , value = rem
           , res = CAST(res + RIGHT('00' + value, 2) 
                      + '.' + RIGHT('00' + rem, 2) as nvarchar(50))
      FROM   Splitter
      WHERE  patindex('%.%', rem) = 0
        AND  rem <> ''
    )
    UPDATE table1 Set
      Data = res
    FROM   table1 t
           INNER JOIN Splitter s ON t.Data = s.Data and s.Pos = 1
    

    SQLFiddle demo

    CTE的anchor查询获取value中的第一个block,将pos设置为block的个数并准备结果(res)。
    运行器查询适用于下一个块,但不适用于最后一个块,搜索第 n 个块并将块添加到结果中。
    停止查询获取最后一个块,不搜索另一个点,不会找到,并完成结果的构造。最初将 pos 设置为块数,现在它将为 1。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-29
      • 1970-01-01
      相关资源
      最近更新 更多